From 910ae6cba950b21c94f57f40ded2d9a922a9294e Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 19 Aug 2013 16:09:08 +0200 Subject: Created chat common javascript module/css/template file bzr revid: nicolas.vanhoren@openerp.com-20130819140908-iai1e58wh7ofb7tp --- addons/im/static/src/js/im_common.js | 440 +++++++++++++++++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 addons/im/static/src/js/im_common.js (limited to 'addons/im/static/src/js') diff --git a/addons/im/static/src/js/im_common.js b/addons/im/static/src/js/im_common.js new file mode 100644 index 00000000000..5307cb422fa --- /dev/null +++ b/addons/im/static/src/js/im_common.js @@ -0,0 +1,440 @@ + +/* + Dependencies: openerp, underscore, jquery + + This file must compile in EcmaScript 3 and work in IE7. + + Prerequisites to use this module: + - load the im_common.xml qweb template into openerp.qweb + - implement all the stuff defined later +*/ + +(function() { + +function declare($, _, openerp) { + /* jshint es3: true */ + "use strict"; + + var im_common = {}; + + // like underscore's noConflit() to easily create an amd wrapper + var tmp_im_common = window.im_common; + im_common.no_conflict = function() { + window.im_common = tmp_im_common; + return im_common; + }; + window.im_common = im_common; + + /* + All of this must be defined to use this module + */ + _.extend(im_common, { + to_url: function(file) { + throw new Error("Not implemented"); + }, + notification: function(message) { + throw new Error("Not implemented"); + }, + defaultInputPlaceholder: null, + userName: null, + connection: null + }); + + var _t = openerp._t; + + var im_common = {}; + + var ERROR_DELAY = 5000; + + im_common.ChatButton = openerp.Widget.extend({ + className: "openerp_style oe_chat_button", + events: { + "click": "click" + }, + init: function(parent, channel, options) { + this._super(parent); + this.channel = channel; + this.options = options; + this.text = options.buttonText; + }, + start: function() { + this.$().append(openerp.qweb.render("chatButton", {widget: this})); + }, + click: function() { + if (! this.manager) { + this.manager = new im_common.ConversationManager(null); + this.activated_def = this.manager.start_polling(); + } + var def = $.Deferred(); + $.when(this.activated_def).then(function() { + def.resolve(); + }, function() { + def.reject(); + }); + setTimeout(function() { + def.reject(); + }, 5000); + def.then(_.bind(this.chat, this), function() { + im_common.notification(_t("It seems the connection to the server is encountering problems, please try again later.")); + }); + }, + chat: function() { + var self = this; + if (this.manager.conversations.length > 0) + return; + im_common.connection.model("im_livechat.channel").call("get_available_user", [this.channel]).then(function(user_id) { + if (! user_id) { + im_common.notification(_t("None of our collaborators seems to be available, please try again later.")); + return; + } + self.manager.ensure_users([user_id]).then(function() { + var conv = self.manager.activate_user(self.manager.get_user(user_id), true); + if (self.options.defaultMessage) { + conv.received_message({message: self.options.defaultMessage, + date: openerp.datetime_to_str(new Date())}); + } + }); + }); + } + }); + + im_common.ImUser = openerp.Class.extend(openerp.PropertiesMixin, { + init: function(parent, user_rec) { + openerp.PropertiesMixin.init.call(this, parent); + user_rec.image_url = im_common.to_url("im/static/src/img/avatar/avatar.jpeg"); + if (user_rec.image) + user_rec.image_url = "data:image/png;base64," + user_rec.image; + this.set(user_rec); + this.set("watcher_count", 0); + this.on("change:watcher_count", this, function() { + if (this.get("watcher_count") === 0) + this.destroy(); + }); + }, + destroy: function() { + this.trigger("destroyed"); + openerp.PropertiesMixin.destroy.call(this); + }, + add_watcher: function() { + this.set("watcher_count", this.get("watcher_count") + 1); + }, + remove_watcher: function() { + this.set("watcher_count", this.get("watcher_count") - 1); + } + }); + + im_common.ConversationManager = openerp.Class.extend(openerp.PropertiesMixin, { + init: function(parent) { + openerp.PropertiesMixin.init.call(this, parent); + this.set("right_offset", 0); + this.conversations = []; + this.users = {}; + this.on("change:right_offset", this, this.calc_positions); + this.set("window_focus", true); + this.set("waiting_messages", 0); + this.focus_hdl = _.bind(function() { + this.set("window_focus", true); + }, this); + $(window).bind("focus", this.focus_hdl); + this.blur_hdl = _.bind(function() { + this.set("window_focus", false); + }, this); + $(window).bind("blur", this.blur_hdl); + this.on("change:window_focus", this, this.window_focus_change); + this.window_focus_change(); + this.on("change:waiting_messages", this, this.messages_change); + this.messages_change(); + this.create_ting(); + this.activated = false; + this.users_cache = {}; + this.last = null; + this.unload_event_handler = _.bind(this.unload, this); + }, + start_polling: function() { + var self = this; + + var uuid = localStorage["oe_livesupport_uuid"]; + var def = $.when(uuid); + + if (! uuid) { + def = im_common.connection.rpc("/longpolling/im/gen_uuid", {}); + } + return def.then(function(uuid) { + localStorage["oe_livesupport_uuid"] = uuid; + return im_common.connection.model("im.user").call("get_by_user_id", [uuid]); + }).then(function(my_id) { + self.my_id = my_id["id"]; + return im_common.connection.model("im.user").call("assign_name", [uuid, im_common.userName]); + }).then(function() { + return self.ensure_users([self.my_id]); + }).then(function() { + var me = self.users_cache[self.my_id]; + delete self.users_cache[self.my_id]; + self.me = me; + me.set("name", "You"); + return im_common.connection.rpc("/longpolling/im/activated", {}); + }).then(function(activated) { + if (activated) { + self.activated = true; + $(window).on("unload", self.unload_event_handler); + self.poll(); + } else { + return $.Deferred().reject(); + } + }); + }, + unload: function() { + im_common.connection.model("im.user").call("im_disconnect", [], {uuid: this.me.get("uuid"), context: {}}); + }, + ensure_users: function(user_ids) { + var no_cache = {}; + _.each(user_ids, function(el) { + if (! this.users_cache[el]) + no_cache[el] = el; + }, this); + var self = this; + if (_.size(no_cache) === 0) + return $.when(); + else + return im_common.connection.model("im.user").call("read", [_.values(no_cache), []]).then(function(users) { + self.add_to_user_cache(users); + }); + }, + add_to_user_cache: function(user_recs) { + _.each(user_recs, function(user_rec) { + if (! this.users_cache[user_rec.id]) { + var user = new im_common.ImUser(this, user_rec); + this.users_cache[user_rec.id] = user; + user.on("destroyed", this, function() { + delete this.users_cache[user_rec.id]; + }); + } + }, this); + }, + get_user: function(user_id) { + return this.users_cache[user_id]; + }, + poll: function() { + console.debug("live support beggin polling"); + var self = this; + var user_ids = _.map(this.users_cache, function(el) { + return el.get("id"); + }); + im_common.connection.rpc("/longpolling/im/poll", { + last: this.last, + users_watch: user_ids, + db: im_common.connection.database, + uid: im_common.connection.userId, + password: im_common.connection.password, + uuid: self.me.get("uuid") + }).then(function(result) { + _.each(result.users_status, function(el) { + if (self.get_user(el.id)) + self.get_user(el.id).set(el); + }); + self.last = result.last; + var user_ids = _.pluck(_.pluck(result.res, "from_id"), 0); + self.ensure_users(user_ids).then(function() { + _.each(result.res, function(mes) { + var user = self.get_user(mes.from_id[0]); + self.received_message(mes, user); + }); + self.poll(); + }); + }, function() { + setTimeout(_.bind(self.poll, self), ERROR_DELAY); + }); + }, + get_activated: function() { + return this.activated; + }, + create_ting: function() { + if (typeof(Audio) === "undefined") { + this.ting = {play: function() {}}; + return; + } + this.ting = new Audio(new Audio().canPlayType("audio/ogg; codecs=vorbis") ? + im_common.to_url("im/static/src/audio/Ting.ogg") : + im_common.to_url("im/static/src/audio/Ting.mp3") + ); + }, + window_focus_change: function() { + if (this.get("window_focus")) { + this.set("waiting_messages", 0); + } + }, + messages_change: function() { + //if (! instance.webclient.set_title_part) + // return; + //instance.webclient.set_title_part("im_messages", this.get("waiting_messages") === 0 ? undefined : + // _.str.sprintf(_t("%d Messages"), this.get("waiting_messages"))); + }, + activate_user: function(user, focus) { + var conv = this.users[user.get('id')]; + if (! conv) { + conv = new im_common.Conversation(this, user, this.me); + conv.appendTo($("body")); + conv.on("destroyed", this, function() { + this.conversations = _.without(this.conversations, conv); + delete this.users[conv.user.get('id')]; + this.calc_positions(); + }); + this.conversations.push(conv); + this.users[user.get('id')] = conv; + this.calc_positions(); + } + if (focus) + conv.focus(); + return conv; + }, + received_message: function(message, user) { + if (! this.get("window_focus")) { + this.set("waiting_messages", this.get("waiting_messages") + 1); + this.ting.play(); + this.create_ting(); + } + var conv = this.activate_user(user); + conv.received_message(message); + }, + calc_positions: function() { + var current = this.get("right_offset"); + _.each(_.range(this.conversations.length), function(i) { + this.conversations[i].set("right_position", current); + current += this.conversations[i].$().outerWidth(true); + }, this); + }, + destroy: function() { + $(window).off("unload", this.unload_event_handler); + $(window).unbind("blur", this.blur_hdl); + $(window).unbind("focus", this.focus_hdl); + openerp.PropertiesMixin.destroy.call(this); + } + }); + + im_common.Conversation = openerp.Widget.extend({ + className: "openerp_style oe_im_chatview", + events: { + "keydown input": "send_message", + "click .oe_im_chatview_close": "destroy", + "click .oe_im_chatview_header": "show_hide" + }, + init: function(parent, user, me) { + this._super(parent); + this.me = me; + this.user = user; + this.user.add_watcher(); + this.set("right_position", 0); + this.shown = true; + this.set("pending", 0); + this.inputPlaceholder = im_common.defaultInputPlaceholder; + }, + start: function() { + this.$().append(openerp.qweb.render("conversation", {widget: this, to_url: im_common.to_url})); + var change_status = function() { + this.$().toggleClass("oe_im_chatview_disconnected_status", this.user.get("im_status") === false); + this.$(".oe_im_chatview_online").toggle(this.user.get("im_status") === true); + this._go_bottom(); + }; + this.user.on("change:im_status", this, change_status); + change_status.call(this); + + this.on("change:right_position", this, this.calc_pos); + this.full_height = this.$().height(); + this.calc_pos(); + this.on("change:pending", this, _.bind(function() { + if (this.get("pending") === 0) { + this.$(".oe_im_chatview_nbr_messages").text(""); + } else { + this.$(".oe_im_chatview_nbr_messages").text("(" + this.get("pending") + ")"); + } + }, this)); + }, + show_hide: function() { + if (this.shown) { + this.$().animate({ + height: this.$(".oe_im_chatview_header").outerHeight() + }); + } else { + this.$().animate({ + height: this.full_height + }); + } + this.shown = ! this.shown; + if (this.shown) { + this.set("pending", 0); + } + }, + calc_pos: function() { + this.$().css("right", this.get("right_position")); + }, + received_message: function(message) { + if (this.shown) { + this.set("pending", 0); + } else { + this.set("pending", this.get("pending") + 1); + } + this._add_bubble(this.user, message.message, openerp.str_to_datetime(message.date)); + }, + send_message: function(e) { + if(e && e.which !== 13) { + return; + } + var mes = this.$("input").val(); + if (! mes.trim()) { + return; + } + this.$("input").val(""); + var send_it = _.bind(function() { + var model = im_common.connection.model("im.message"); + return model.call("post", [mes, this.user.get('id')], {uuid: this.me.get("uuid"), context: {}}); + }, this); + var tries = 0; + send_it().then(_.bind(function() { + this._add_bubble(this.me, mes, new Date()); + }, this), function(error, e) { + tries += 1; + if (tries < 3) + return send_it(); + }); + }, + _add_bubble: function(user, item, date) { + var items = [item]; + if (user === this.last_user) { + this.last_bubble.remove(); + items = this.last_items.concat(items); + } + this.last_user = user; + this.last_items = items; + var zpad = function(str, size) { + str = "" + str; + return new Array(size - str.length + 1).join('0') + str; + }; + date = "" + zpad(date.getHours(), 2) + ":" + zpad(date.getMinutes(), 2); + + this.last_bubble = $(openerp.qweb.render("conversation_bubble", {"items": items, "user": user, "time": date})); + $(this.$(".oe_im_chatview_content").children()[0]).append(this.last_bubble); + this._go_bottom(); + }, + _go_bottom: function() { + this.$(".oe_im_chatview_content").scrollTop($(this.$(".oe_im_chatview_content").children()[0]).height()); + }, + focus: function() { + this.$(".oe_im_chatview_input").focus(); + }, + destroy: function() { + this.user.remove_watcher(); + this.trigger("destroyed"); + return this._super(); + } + }); + + return im_common; +} + +if (typeof(define) !== undefined) { + define(["jquery", "underscore", "openerp"], declare); +} else { + window.im_common = declare($, _, openerp); +} + +})(); -- cgit v1.2.3 From c2366d71810ea4a2860f75dbd482dd12649318a8 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 19 Aug 2013 16:21:39 +0200 Subject: Put ChatButton in livechat bzr revid: nicolas.vanhoren@openerp.com-20130819142139-mvh25k95k1wbjtzv --- addons/im/static/src/js/im_common.js | 62 ------------------------------------ 1 file changed, 62 deletions(-) (limited to 'addons/im/static/src/js') diff --git a/addons/im/static/src/js/im_common.js b/addons/im/static/src/js/im_common.js index 5307cb422fa..e9226e4c056 100644 --- a/addons/im/static/src/js/im_common.js +++ b/addons/im/static/src/js/im_common.js @@ -1,7 +1,5 @@ /* - Dependencies: openerp, underscore, jquery - This file must compile in EcmaScript 3 and work in IE7. Prerequisites to use this module: @@ -17,14 +15,6 @@ function declare($, _, openerp) { var im_common = {}; - // like underscore's noConflit() to easily create an amd wrapper - var tmp_im_common = window.im_common; - im_common.no_conflict = function() { - window.im_common = tmp_im_common; - return im_common; - }; - window.im_common = im_common; - /* All of this must be defined to use this module */ @@ -46,58 +36,6 @@ function declare($, _, openerp) { var ERROR_DELAY = 5000; - im_common.ChatButton = openerp.Widget.extend({ - className: "openerp_style oe_chat_button", - events: { - "click": "click" - }, - init: function(parent, channel, options) { - this._super(parent); - this.channel = channel; - this.options = options; - this.text = options.buttonText; - }, - start: function() { - this.$().append(openerp.qweb.render("chatButton", {widget: this})); - }, - click: function() { - if (! this.manager) { - this.manager = new im_common.ConversationManager(null); - this.activated_def = this.manager.start_polling(); - } - var def = $.Deferred(); - $.when(this.activated_def).then(function() { - def.resolve(); - }, function() { - def.reject(); - }); - setTimeout(function() { - def.reject(); - }, 5000); - def.then(_.bind(this.chat, this), function() { - im_common.notification(_t("It seems the connection to the server is encountering problems, please try again later.")); - }); - }, - chat: function() { - var self = this; - if (this.manager.conversations.length > 0) - return; - im_common.connection.model("im_livechat.channel").call("get_available_user", [this.channel]).then(function(user_id) { - if (! user_id) { - im_common.notification(_t("None of our collaborators seems to be available, please try again later.")); - return; - } - self.manager.ensure_users([user_id]).then(function() { - var conv = self.manager.activate_user(self.manager.get_user(user_id), true); - if (self.options.defaultMessage) { - conv.received_message({message: self.options.defaultMessage, - date: openerp.datetime_to_str(new Date())}); - } - }); - }); - } - }); - im_common.ImUser = openerp.Class.extend(openerp.PropertiesMixin, { init: function(parent, user_rec) { openerp.PropertiesMixin.init.call(this, parent); -- cgit v1.2.3 From d60c2a5f7e032d7636caef1bb17b5e893efd6e7c Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 20 Aug 2013 14:15:22 +0200 Subject: Some cleaning bzr revid: nicolas.vanhoren@openerp.com-20130820121522-en3bft0wotfnsozm --- addons/im/static/src/js/im_common.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'addons/im/static/src/js') diff --git a/addons/im/static/src/js/im_common.js b/addons/im/static/src/js/im_common.js index e9226e4c056..2768627f951 100644 --- a/addons/im/static/src/js/im_common.js +++ b/addons/im/static/src/js/im_common.js @@ -25,8 +25,6 @@ function declare($, _, openerp) { notification: function(message) { throw new Error("Not implemented"); }, - defaultInputPlaceholder: null, - userName: null, connection: null }); @@ -62,8 +60,9 @@ function declare($, _, openerp) { }); im_common.ConversationManager = openerp.Class.extend(openerp.PropertiesMixin, { - init: function(parent) { + init: function(parent, options) { openerp.PropertiesMixin.init.call(this, parent); + this.options = options; this.set("right_offset", 0); this.conversations = []; this.users = {}; @@ -102,7 +101,7 @@ function declare($, _, openerp) { return im_common.connection.model("im.user").call("get_by_user_id", [uuid]); }).then(function(my_id) { self.my_id = my_id["id"]; - return im_common.connection.model("im.user").call("assign_name", [uuid, im_common.userName]); + return im_common.connection.model("im.user").call("assign_name", [uuid, self.options.userName]); }).then(function() { return self.ensure_users([self.my_id]); }).then(function() { @@ -210,7 +209,7 @@ function declare($, _, openerp) { activate_user: function(user, focus) { var conv = this.users[user.get('id')]; if (! conv) { - conv = new im_common.Conversation(this, user, this.me); + conv = new im_common.Conversation(this, user, this.me, this.options); conv.appendTo($("body")); conv.on("destroyed", this, function() { this.conversations = _.without(this.conversations, conv); @@ -256,18 +255,19 @@ function declare($, _, openerp) { "click .oe_im_chatview_close": "destroy", "click .oe_im_chatview_header": "show_hide" }, - init: function(parent, user, me) { + init: function(parent, user, me, options) { this._super(parent); + this.options = options this.me = me; this.user = user; this.user.add_watcher(); this.set("right_position", 0); this.shown = true; this.set("pending", 0); - this.inputPlaceholder = im_common.defaultInputPlaceholder; + this.inputPlaceholder = this.options.defaultInputPlaceholder; }, start: function() { - this.$().append(openerp.qweb.render("conversation", {widget: this, to_url: im_common.to_url})); + this.$().append(openerp.qweb.render("im_common.conversation", {widget: this, to_url: im_common.to_url})); var change_status = function() { this.$().toggleClass("oe_im_chatview_disconnected_status", this.user.get("im_status") === false); this.$(".oe_im_chatview_online").toggle(this.user.get("im_status") === true); @@ -349,7 +349,7 @@ function declare($, _, openerp) { }; date = "" + zpad(date.getHours(), 2) + ":" + zpad(date.getMinutes(), 2); - this.last_bubble = $(openerp.qweb.render("conversation_bubble", {"items": items, "user": user, "time": date})); + this.last_bubble = $(openerp.qweb.render("im_common.conversation_bubble", {"items": items, "user": user, "time": date})); $(this.$(".oe_im_chatview_content").children()[0]).append(this.last_bubble); this._go_bottom(); }, -- cgit v1.2.3 From 980952c416a43316068a7315fb562518e11da36b Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 20 Aug 2013 16:15:38 +0200 Subject: Ported most of the old im.js to im_common.js bzr revid: nicolas.vanhoren@openerp.com-20130820141538-xsdm64uinhbf8v5g --- addons/im/static/src/js/im.js | 332 ++--------------------------------- addons/im/static/src/js/im_common.js | 93 ++++++---- 2 files changed, 71 insertions(+), 354 deletions(-) (limited to 'addons/im/static/src/js') diff --git a/addons/im/static/src/js/im.js b/addons/im/static/src/js/im.js index a271c9eccf0..83195d8a5d1 100644 --- a/addons/im/static/src/js/im.js +++ b/addons/im/static/src/js/im.js @@ -4,14 +4,21 @@ openerp.im = function(instance) { var USERS_LIMIT = 20; var ERROR_DELAY = 5000; - var _t = instance.web._t, - _lt = instance.web._lt; + var _t = instance.web._t; var QWeb = instance.web.qweb; instance.web.UserMenu.include({ do_update: function(){ var self = this; this.update_promise.then(function() { + im_common.notification = function(message) { + instance.client.do_warn(message); + }; + im_common.to_url = function(file) { + return "/" + file; + }; + im_common.connection = openerp.session; + var im = new instance.im.InstantMessaging(self); im.appendTo(instance.client.$el); var button = new instance.im.ImTopButton(this); @@ -45,7 +52,7 @@ openerp.im = function(instance) { this.set("right_offset", 0); this.set("current_search", ""); this.users = []; - this.c_manager = new instance.im.ConversationManager(this); + this.c_manager = new im_common.ConversationManager(this); this.on("change:right_offset", this.c_manager, _.bind(function() { this.c_manager.set("right_offset", this.get("right_offset")); }, this)); @@ -148,323 +155,4 @@ openerp.im = function(instance) { }, }); - instance.im.ImUser = instance.web.Class.extend(instance.web.PropertiesMixin, { - init: function(parent, user_rec) { - instance.web.PropertiesMixin.init.call(this, parent); - user_rec.image_url = instance.session.url("/im/static/src/img/avatar/avatar.jpeg"); - if (user_rec.user) - user_rec.image_url = instance.session.url('/web/binary/image', {model:'res.users', field: 'image_small', id: user_rec.user[0]}); - this.set(user_rec); - this.set("watcher_count", 0); - this.on("change:watcher_count", this, function() { - if (this.get("watcher_count") === 0) - this.destroy(); - }); - }, - destroy: function() { - this.trigger("destroyed"); - instance.web.PropertiesMixin.destroy.call(this); - }, - add_watcher: function() { - this.set("watcher_count", this.get("watcher_count") + 1); - }, - remove_watcher: function() { - this.set("watcher_count", this.get("watcher_count") - 1); - }, - }); - - instance.im.ConversationManager = instance.web.Controller.extend({ - init: function(parent) { - this._super(parent); - this.set("right_offset", 0); - this.conversations = []; - this.users = {}; - this.on("change:right_offset", this, this.calc_positions); - this.set("window_focus", true); - this.set("waiting_messages", 0); - this.focus_hdl = _.bind(function() { - this.set("window_focus", true); - }, this); - $(window).bind("focus", this.focus_hdl); - this.blur_hdl = _.bind(function() { - this.set("window_focus", false); - }, this); - $(window).bind("blur", this.blur_hdl); - this.on("change:window_focus", this, this.window_focus_change); - this.window_focus_change(); - this.on("change:waiting_messages", this, this.messages_change); - this.messages_change(); - this.create_ting(); - this.activated = false; - this.users_cache = {}; - this.last = null; - this.unload_event_handler = _.bind(this.unload, this); - }, - start_polling: function() { - var self = this; - return new instance.web.Model("im.user").call("get_by_user_id", [instance.session.uid]).then(function(my_id) { - self.my_id = my_id["id"]; - return self.ensure_users([self.my_id]).then(function() { - var me = self.users_cache[self.my_id]; - delete self.users_cache[self.my_id]; - self.me = me; - self.rpc("/longpolling/im/activated", {}, {shadow: true}).then(function(activated) { - if (activated) { - self.activated = true; - $(window).on("unload", self.unload_event_handler); - self.poll(); - } - }, function(a, e) { - e.preventDefault(); - }); - }); - }); - }, - unload: function() { - return new instance.web.Model("im.user").call("im_disconnect", [], {context: new instance.web.CompoundContext()}); - }, - ensure_users: function(user_ids) { - var no_cache = {}; - _.each(user_ids, function(el) { - if (! this.users_cache[el]) - no_cache[el] = el; - }, this); - var self = this; - if (_.size(no_cache) === 0) - return $.when(); - else - return new instance.web.Model("im.user").call("read", [_.values(no_cache), ["name", "user", "uuid", "im_status"]], - {context: new instance.web.CompoundContext()}).then(function(users) { - self.add_to_user_cache(users); - }); - }, - add_to_user_cache: function(user_recs) { - _.each(user_recs, function(user_rec) { - if (! this.users_cache[user_rec.id]) { - var user = new instance.im.ImUser(this, user_rec); - this.users_cache[user_rec.id] = user; - user.on("destroyed", this, function() { - delete this.users_cache[user_rec.id]; - }); - } - }, this); - }, - get_user: function(user_id) { - return this.users_cache[user_id]; - }, - poll: function() { - var self = this; - var user_ids = _.map(this.users_cache, function(el) { - return el.get("id"); - }); - this.rpc("/longpolling/im/poll", { - last: this.last, - users_watch: user_ids, - context: instance.web.pyeval.eval('context', {}), - }, {shadow: true}).then(function(result) { - _.each(result.users_status, function(el) { - if (self.get_user(el.id)) - self.get_user(el.id).set(el); - }); - self.last = result.last; - var user_ids = _.pluck(_.pluck(result.res, "from_id"), 0); - self.ensure_users(user_ids).then(function() { - _.each(result.res, function(mes) { - var user = self.get_user(mes.from_id[0]); - self.received_message(mes, user); - }); - self.poll(); - }); - }, function(unused, e) { - e.preventDefault(); - setTimeout(_.bind(self.poll, self), ERROR_DELAY); - }); - }, - get_activated: function() { - return this.activated; - }, - create_ting: function() { - if (typeof(Audio) === "undefined") { - this.ting = {play: function() {}}; - return; - } - var kitten = jQuery.param !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined; - this.ting = new Audio(instance.webclient.session.origin + "/im/static/src/audio/" + (kitten ? "purr" : "Ting") + - (new Audio().canPlayType("audio/ogg; codecs=vorbis") ? ".ogg" : ".mp3")); - }, - window_focus_change: function() { - if (this.get("window_focus")) { - this.set("waiting_messages", 0); - } - }, - messages_change: function() { - if (! instance.webclient.set_title_part) - return; - instance.webclient.set_title_part("aa_im_messages", this.get("waiting_messages") === 0 ? undefined : - _.str.sprintf(_t("%d Messages"), this.get("waiting_messages"))); - }, - activate_user: function(user, focus) { - var conv = this.users[user.get('id')]; - if (! conv) { - conv = new instance.im.Conversation(this, user, this.me); - conv.appendTo(instance.client.$el); - conv.on("destroyed", this, function() { - this.conversations = _.without(this.conversations, conv); - delete this.users[conv.user.get('id')]; - this.calc_positions(); - }); - this.conversations.push(conv); - this.users[user.get('id')] = conv; - this.calc_positions(); - } - if (focus) - conv.focus(); - return conv; - }, - received_message: function(message, user) { - if (! this.get("window_focus")) { - this.set("waiting_messages", this.get("waiting_messages") + 1); - this.ting.play(); - this.create_ting(); - } - var conv = this.activate_user(user); - conv.received_message(message); - }, - calc_positions: function() { - var current = this.get("right_offset"); - _.each(_.range(this.conversations.length), function(i) { - this.conversations[i].set("right_position", current); - current += this.conversations[i].$el.outerWidth(true); - }, this); - }, - destroy: function() { - $(window).off("unload", this.unload_event_handler); - $(window).unbind("blur", this.blur_hdl); - $(window).unbind("focus", this.focus_hdl); - this._super(); - }, - }); - - instance.im.Conversation = instance.web.Widget.extend({ - "template": "Conversation", - events: { - "keydown input": "send_message", - "click .oe_im_chatview_close": "destroy", - "click .oe_im_chatview_header": "show_hide", - }, - init: function(parent, user, me) { - this._super(parent); - this.me = me; - this.user = user; - this.user.add_watcher(); - this.set("right_position", 0); - this.shown = true; - this.set("pending", 0); - }, - start: function() { - var change_status = function() { - this.$el.toggleClass("oe_im_chatview_disconnected_status", this.user.get("im_status") === false); - this.$(".oe_im_chatview_online").toggle(this.user.get("im_status") === true); - this._go_bottom(); - }; - this.user.on("change:im_status", this, change_status); - change_status.call(this); - - this.on("change:right_position", this, this.calc_pos); - this.full_height = this.$el.height(); - this.calc_pos(); - this.on("change:pending", this, _.bind(function() { - if (this.get("pending") === 0) { - this.$(".oe_im_chatview_nbr_messages").text(""); - } else { - this.$(".oe_im_chatview_nbr_messages").text("(" + this.get("pending") + ")"); - } - }, this)); - }, - show_hide: function() { - if (this.shown) { - this.$el.animate({ - height: this.$(".oe_im_chatview_header").outerHeight(), - }); - } else { - this.$el.animate({ - height: this.full_height, - }); - } - this.shown = ! this.shown; - if (this.shown) { - this.set("pending", 0); - } - }, - calc_pos: function() { - this.$el.css("right", this.get("right_position")); - }, - received_message: function(message) { - if (this.shown) { - this.set("pending", 0); - } else { - this.set("pending", this.get("pending") + 1); - } - this._add_bubble(this.user, message.message, message.date); - }, - send_message: function(e) { - if(e && e.which !== 13) { - return; - } - var mes = this.$("input").val(); - if (! mes.trim()) { - return; - } - this.$("input").val(""); - var send_it = _.bind(function() { - var model = new instance.web.Model("im.message"); - return model.call("post", [mes, this.user.get('id')], - {context: new instance.web.CompoundContext()}); - }, this); - var tries = 0; - send_it().then(_.bind(function() { - this._add_bubble(this.me, mes, instance.web.datetime_to_str(new Date())); - }, this), function(error, e) { - e.preventDefault(); - tries += 1; - if (tries < 3) - return send_it(); - }); - }, - _add_bubble: function(user, item, date) { - var items = [item]; - if (user === this.last_user) { - this.last_bubble.remove(); - items = this.last_items.concat(items); - } - this.last_user = user; - this.last_items = items; - date = instance.web.str_to_datetime(date); - var now = new Date(); - var diff = now - date; - if (diff > (1000 * 60 * 60 * 24)) { - date = $.timeago(date); - } else { - date = date.toString(Date.CultureInfo.formatPatterns.shortTime); - } - - this.last_bubble = $(QWeb.render("Conversation.bubble", {"items": items, "user": user, "time": date})); - $(this.$(".oe_im_chatview_content").children()[0]).append(this.last_bubble); - this._go_bottom(); - }, - _go_bottom: function() { - this.$(".oe_im_chatview_content").scrollTop($(this.$(".oe_im_chatview_content").children()[0]).height()); - }, - focus: function() { - this.$(".oe_im_chatview_input").focus(); - if (! this.shown) - this.show_hide(); - }, - destroy: function() { - this.user.remove_watcher(); - this.trigger("destroyed"); - return this._super(); - }, - }); - } \ No newline at end of file diff --git a/addons/im/static/src/js/im_common.js b/addons/im/static/src/js/im_common.js index 2768627f951..7802947967d 100644 --- a/addons/im/static/src/js/im_common.js +++ b/addons/im/static/src/js/im_common.js @@ -38,8 +38,13 @@ function declare($, _, openerp) { init: function(parent, user_rec) { openerp.PropertiesMixin.init.call(this, parent); user_rec.image_url = im_common.to_url("im/static/src/img/avatar/avatar.jpeg"); - if (user_rec.image) - user_rec.image_url = "data:image/png;base64," + user_rec.image; + + // TODO : check it works correctly + if (user_rec.user) + user_rec.image_url = im_common.connection.url('/web/binary/image', {model:'res.users', field: 'image_small', id: user_rec.user[0]}); + /*if (user_rec.image) + user_rec.image_url = "data:image/png;base64," + user_rec.image;*/ + this.set(user_rec); this.set("watcher_count", 0); this.on("change:watcher_count", this, function() { @@ -62,7 +67,13 @@ function declare($, _, openerp) { im_common.ConversationManager = openerp.Class.extend(openerp.PropertiesMixin, { init: function(parent, options) { openerp.PropertiesMixin.init.call(this, parent); - this.options = options; + this.options = _.clone(options) || {}; + _.defaults(this.options, { + inputPlaceholder: _t("Say something..."), + defaultMessage: null, + userName: _t("Anonymous"), + anonymous_mode: false + }); this.set("right_offset", 0); this.conversations = []; this.users = {}; @@ -90,26 +101,40 @@ function declare($, _, openerp) { start_polling: function() { var self = this; - var uuid = localStorage["oe_livesupport_uuid"]; - var def = $.when(uuid); + var auth_def = null; + var user_id = null; - if (! uuid) { - def = im_common.connection.rpc("/longpolling/im/gen_uuid", {}); + if (this.options.anonymous_mode) { + var uuid = localStorage["oe_livesupport_uuid"]; + var def = $.when(uuid); + + if (! uuid) { + def = im_common.connection.rpc("/longpolling/im/gen_uuid", {}); + } + var anonymous_user_id = null; + auth_def = def.then(function(uuid) { + localStorage["oe_livesupport_uuid"] = uuid; + return im_common.connection.model("im.user").call("get_by_user_id", [uuid]); + }).then(function(my_id) { + user_id = my_id["id"]; + return im_common.connection.model("im.user").call("assign_name", [uuid, self.options.userName]); + }); + } else { + auth_def = im_common.connection.model("im.user").call("get_by_user_id", + [im_common.connection.uid]).then(function(my_id) { + user_id = my_id["id"]; + }); } - return def.then(function(uuid) { - localStorage["oe_livesupport_uuid"] = uuid; - return im_common.connection.model("im.user").call("get_by_user_id", [uuid]); - }).then(function(my_id) { - self.my_id = my_id["id"]; - return im_common.connection.model("im.user").call("assign_name", [uuid, self.options.userName]); - }).then(function() { + + auth_def.then(function() { + self.my_id = user_id; return self.ensure_users([self.my_id]); }).then(function() { var me = self.users_cache[self.my_id]; delete self.users_cache[self.my_id]; self.me = me; - me.set("name", "You"); - return im_common.connection.rpc("/longpolling/im/activated", {}); + me.set("name", _t("You")); + return im_common.connection.rpc("/longpolling/im/activated", {}, {shadow: true}); }).then(function(activated) { if (activated) { self.activated = true; @@ -118,10 +143,12 @@ function declare($, _, openerp) { } else { return $.Deferred().reject(); } + }, function(a, e) { + e.preventDefault(); }); }, unload: function() { - im_common.connection.model("im.user").call("im_disconnect", [], {uuid: this.me.get("uuid"), context: {}}); + return im_common.connection.model("im.user").call("im_disconnect", [], {uuid: this.me.get("uuid"), context: {}}); }, ensure_users: function(user_ids) { var no_cache = {}; @@ -152,7 +179,6 @@ function declare($, _, openerp) { return this.users_cache[user_id]; }, poll: function() { - console.debug("live support beggin polling"); var self = this; var user_ids = _.map(this.users_cache, function(el) { return el.get("id"); @@ -160,11 +186,8 @@ function declare($, _, openerp) { im_common.connection.rpc("/longpolling/im/poll", { last: this.last, users_watch: user_ids, - db: im_common.connection.database, - uid: im_common.connection.userId, - password: im_common.connection.password, uuid: self.me.get("uuid") - }).then(function(result) { + }, {shadow: true}).then(function(result) { _.each(result.users_status, function(el) { if (self.get_user(el.id)) self.get_user(el.id).set(el); @@ -178,7 +201,8 @@ function declare($, _, openerp) { }); self.poll(); }); - }, function() { + }, function(unused, e) { + e.preventDefault(); setTimeout(_.bind(self.poll, self), ERROR_DELAY); }); }, @@ -190,10 +214,12 @@ function declare($, _, openerp) { this.ting = {play: function() {}}; return; } - this.ting = new Audio(new Audio().canPlayType("audio/ogg; codecs=vorbis") ? - im_common.to_url("im/static/src/audio/Ting.ogg") : - im_common.to_url("im/static/src/audio/Ting.mp3") - ); + var kitten = jQuery.deparam !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined; + this.ting = new Audio(im_common.to_url( + "im/static/src/audio/" + + (kitten ? "purr" : "Ting") + + (new Audio().canPlayType("audio/ogg; codecs=vorbis") ? ".ogg": ".mp3") + )); }, window_focus_change: function() { if (this.get("window_focus")) { @@ -201,10 +227,10 @@ function declare($, _, openerp) { } }, messages_change: function() { - //if (! instance.webclient.set_title_part) - // return; - //instance.webclient.set_title_part("im_messages", this.get("waiting_messages") === 0 ? undefined : - // _.str.sprintf(_t("%d Messages"), this.get("waiting_messages"))); + if (! openerp.webclient || !openerp.webclient.set_title_part) + return; + openerp.webclient.set_title_part("im_messages", this.get("waiting_messages") === 0 ? undefined : + _.str.sprintf(_t("%d Messages"), this.get("waiting_messages"))); }, activate_user: function(user, focus) { var conv = this.users[user.get('id')]; @@ -330,6 +356,7 @@ function declare($, _, openerp) { send_it().then(_.bind(function() { this._add_bubble(this.me, mes, new Date()); }, this), function(error, e) { + e.preventDefault(); tries += 1; if (tries < 3) return send_it(); @@ -358,6 +385,8 @@ function declare($, _, openerp) { }, focus: function() { this.$(".oe_im_chatview_input").focus(); + if (! this.shown) + this.show_hide(); }, destroy: function() { this.user.remove_watcher(); @@ -369,7 +398,7 @@ function declare($, _, openerp) { return im_common; } -if (typeof(define) !== undefined) { +if (typeof(define) !== "undefined") { define(["jquery", "underscore", "openerp"], declare); } else { window.im_common = declare($, _, openerp); -- cgit v1.2.3 From 124b93b0c10e58a5d8cf6b81088a2a585337707e Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 20 Aug 2013 16:41:47 +0200 Subject: Fixed a lot of stuff to make it work again in live support bzr revid: nicolas.vanhoren@openerp.com-20130820144147-gnc26ul3ql86qfzs --- addons/im/static/src/js/im.js | 1 - addons/im/static/src/js/im_common.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'addons/im/static/src/js') diff --git a/addons/im/static/src/js/im.js b/addons/im/static/src/js/im.js index 83195d8a5d1..f0f1771537b 100644 --- a/addons/im/static/src/js/im.js +++ b/addons/im/static/src/js/im.js @@ -2,7 +2,6 @@ openerp.im = function(instance) { var USERS_LIMIT = 20; - var ERROR_DELAY = 5000; var _t = instance.web._t; var QWeb = instance.web.qweb; diff --git a/addons/im/static/src/js/im_common.js b/addons/im/static/src/js/im_common.js index 7802947967d..d89474f32f5 100644 --- a/addons/im/static/src/js/im_common.js +++ b/addons/im/static/src/js/im_common.js @@ -126,7 +126,7 @@ function declare($, _, openerp) { }); } - auth_def.then(function() { + return auth_def.then(function() { self.my_id = user_id; return self.ensure_users([self.my_id]); }).then(function() { -- cgit v1.2.3 From d756dc5977130a1bde68d47febc725b4cf14ac0a Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 20 Aug 2013 16:48:43 +0200 Subject: Removed to_url bzr revid: nicolas.vanhoren@openerp.com-20130820144843-yeny7kpv1qcqijl9 --- addons/im/static/src/js/im.js | 3 --- addons/im/static/src/js/im_common.js | 11 ++++------- 2 files changed, 4 insertions(+), 10 deletions(-) (limited to 'addons/im/static/src/js') diff --git a/addons/im/static/src/js/im.js b/addons/im/static/src/js/im.js index f0f1771537b..8e21167cc9a 100644 --- a/addons/im/static/src/js/im.js +++ b/addons/im/static/src/js/im.js @@ -13,9 +13,6 @@ openerp.im = function(instance) { im_common.notification = function(message) { instance.client.do_warn(message); }; - im_common.to_url = function(file) { - return "/" + file; - }; im_common.connection = openerp.session; var im = new instance.im.InstantMessaging(self); diff --git a/addons/im/static/src/js/im_common.js b/addons/im/static/src/js/im_common.js index d89474f32f5..72097c35f79 100644 --- a/addons/im/static/src/js/im_common.js +++ b/addons/im/static/src/js/im_common.js @@ -19,9 +19,6 @@ function declare($, _, openerp) { All of this must be defined to use this module */ _.extend(im_common, { - to_url: function(file) { - throw new Error("Not implemented"); - }, notification: function(message) { throw new Error("Not implemented"); }, @@ -37,7 +34,7 @@ function declare($, _, openerp) { im_common.ImUser = openerp.Class.extend(openerp.PropertiesMixin, { init: function(parent, user_rec) { openerp.PropertiesMixin.init.call(this, parent); - user_rec.image_url = im_common.to_url("im/static/src/img/avatar/avatar.jpeg"); + user_rec.image_url = im_common.connection.url("/im/static/src/img/avatar/avatar.jpeg"); // TODO : check it works correctly if (user_rec.user) @@ -215,8 +212,8 @@ function declare($, _, openerp) { return; } var kitten = jQuery.deparam !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined; - this.ting = new Audio(im_common.to_url( - "im/static/src/audio/" + + this.ting = new Audio(im_common.connection.url( + "/im/static/src/audio/" + (kitten ? "purr" : "Ting") + (new Audio().canPlayType("audio/ogg; codecs=vorbis") ? ".ogg": ".mp3") )); @@ -293,7 +290,7 @@ function declare($, _, openerp) { this.inputPlaceholder = this.options.defaultInputPlaceholder; }, start: function() { - this.$().append(openerp.qweb.render("im_common.conversation", {widget: this, to_url: im_common.to_url})); + this.$().append(openerp.qweb.render("im_common.conversation", {widget: this, to_url: _.bind(im_common.connection.url, im_common.connection)})); var change_status = function() { this.$().toggleClass("oe_im_chatview_disconnected_status", this.user.get("im_status") === false); this.$(".oe_im_chatview_online").toggle(this.user.get("im_status") === true); -- cgit v1.2.3 From 1d5f220d128588b6055180bc61ec5ff58aa4619c Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 20 Aug 2013 17:06:07 +0200 Subject: Solved bottom offset problem bzr revid: nicolas.vanhoren@openerp.com-20130820150607-btn650h12nygofcm --- addons/im/static/src/js/im_common.js | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'addons/im/static/src/js') diff --git a/addons/im/static/src/js/im_common.js b/addons/im/static/src/js/im_common.js index 72097c35f79..d1a67d26d59 100644 --- a/addons/im/static/src/js/im_common.js +++ b/addons/im/static/src/js/im_common.js @@ -72,9 +72,11 @@ function declare($, _, openerp) { anonymous_mode: false }); this.set("right_offset", 0); + this.set("bottom_offset", 0); this.conversations = []; this.users = {}; this.on("change:right_offset", this, this.calc_positions); + this.on("change:bottom_offset", this, this.calc_positions); this.set("window_focus", true); this.set("waiting_messages", 0); this.focus_hdl = _.bind(function() { @@ -259,6 +261,7 @@ function declare($, _, openerp) { calc_positions: function() { var current = this.get("right_offset"); _.each(_.range(this.conversations.length), function(i) { + this.conversations[i].set("bottom_position", this.get("bottom_offset")); this.conversations[i].set("right_position", current); current += this.conversations[i].$().outerWidth(true); }, this); @@ -285,6 +288,7 @@ function declare($, _, openerp) { this.user = user; this.user.add_watcher(); this.set("right_position", 0); + this.set("bottom_position", 0); this.shown = true; this.set("pending", 0); this.inputPlaceholder = this.options.defaultInputPlaceholder; @@ -300,6 +304,7 @@ function declare($, _, openerp) { change_status.call(this); this.on("change:right_position", this, this.calc_pos); + this.on("change:bottom_position", this, this.calc_pos); this.full_height = this.$().height(); this.calc_pos(); this.on("change:pending", this, _.bind(function() { @@ -327,6 +332,7 @@ function declare($, _, openerp) { }, calc_pos: function() { this.$().css("right", this.get("right_position")); + this.$().css("bottom", this.get("bottom_position")); }, received_message: function(message) { if (this.shown) { -- cgit v1.2.3 From 89b3edad09c7ab1aa292612543aaa2234fe5a51c Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 20 Aug 2013 17:12:41 +0200 Subject: Solved style problems identified by jshint bzr revid: nicolas.vanhoren@openerp.com-20130820151241-1oi29vxm8iq34v8x --- addons/im/static/src/js/im.js | 9 +++++++-- addons/im/static/src/js/im_common.js | 4 +--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'addons/im/static/src/js') diff --git a/addons/im/static/src/js/im.js b/addons/im/static/src/js/im.js index 8e21167cc9a..9af04bf4f43 100644 --- a/addons/im/static/src/js/im.js +++ b/addons/im/static/src/js/im.js @@ -1,5 +1,10 @@ -openerp.im = function(instance) { +(function() { + "use strict"; + + var instance = openerp; + + openerp.im = {}; var USERS_LIMIT = 20; @@ -151,4 +156,4 @@ openerp.im = function(instance) { }, }); -} \ No newline at end of file +})(); \ No newline at end of file diff --git a/addons/im/static/src/js/im_common.js b/addons/im/static/src/js/im_common.js index d1a67d26d59..a6314a978e2 100644 --- a/addons/im/static/src/js/im_common.js +++ b/addons/im/static/src/js/im_common.js @@ -26,8 +26,6 @@ function declare($, _, openerp) { }); var _t = openerp._t; - - var im_common = {}; var ERROR_DELAY = 5000; @@ -283,7 +281,7 @@ function declare($, _, openerp) { }, init: function(parent, user, me, options) { this._super(parent); - this.options = options + this.options = options; this.me = me; this.user = user; this.user.add_watcher(); -- cgit v1.2.3