1 openerp_mail_followers = function(session, mail) {
2 var _t = session.web._t,
5 var mail_followers = session.mail_followers = {};
8 * ------------------------------------------------------------
9 * mail_followers Widget
10 * ------------------------------------------------------------
12 * This widget handles the display of a list of records as a vertical
13 * list, with an image on the left. The widget itself is a floatting
15 * This widget is mainly used to display the followers of records
19 /* Add the widget to registry */
20 session.web.form.widgets.add('mail_followers', 'openerp.mail_followers.Followers');
22 mail_followers.Followers = session.web.form.AbstractField.extend({
23 template: 'mail.followers',
26 this._super.apply(this, arguments);
27 this.image = this.node.attrs.image || 'image_small';
28 this.comment = this.node.attrs.help || false;
29 this.displayed_nb = this.node.attrs.displayed_nb || 10;
30 this.ds_model = new session.web.DataSetSearch(this, this.view.model);
31 this.ds_follow = new session.web.DataSetSearch(this, this.field.relation);
32 this.ds_users = new session.web.DataSetSearch(this, 'res.users');
38 // use actual_mode property on view to know if the view is in create mode anymore
39 this.view.on("change:actual_mode", this, this.on_check_visibility_mode);
40 this.on_check_visibility_mode();
46 on_check_visibility_mode: function () {
47 this.set({"force_invisible": this.view.get("actual_mode") == "create"});
50 set_value: function(_value) {
56 this.message_is_follower == undefined;
57 this.display_buttons();
60 bind_events: function() {
62 // event: click on '(Un)Follow' button, that toggles the follow for uid
63 this.$('.oe_follower').on('click', function (event) {
64 if($(this).hasClass('oe_notfollow'))
69 // event: click on a subtype, that (un)subscribe for this subtype
70 this.$el.on('click', '.oe_subtype_list input', self.do_update_subscription);
71 // event: click on 'invite' button, that opens the invite wizard
72 this.$('.oe_invite').on('click', function (event) {
74 type: 'ir.actions.act_window',
75 res_model: 'mail.wizard.invite',
78 views: [[false, 'form']],
81 'default_res_model': self.view.dataset.model,
82 'default_res_id': self.view.datarecord.id,
85 self.do_action(action, {
86 on_close: function() {
93 read_value: function () {
95 return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).then(function (results) {
96 self.value = results[0].message_follower_ids;
101 render_value: function () {
103 return this.fetch_followers(this.value);
106 fetch_followers: function (value_) {
107 this.value = value_ || {};
108 return this.ds_follow.call('read', [this.value, ['name', 'user_ids']])
109 .then(this.proxy('display_followers'), this.proxy('fetch_generic'))
110 .then(this.proxy('display_buttons'))
111 .then(this.proxy('fetch_subtypes'));
114 /** Read on res.partner failed: fall back on a generic case
115 - fetch current user partner_id (call because no other smart solution currently) FIXME
116 - then display a generic message about followers */
117 fetch_generic: function (error, event) {
119 event.preventDefault();
120 return this.ds_users.call('read', [this.session.uid, ['partner_id']]).then(function (results) {
121 var pid = results['partner_id'][0];
122 self.message_is_follower = (_.indexOf(self.value, pid) != -1);
123 }).then(self.proxy('display_generic'));
125 _format_followers: function(count){
126 // TDE note: why redefining _t ?
127 function _t(str) { return str; }
130 str = _t('No followers');
131 }else if(count === 1){
132 str = _t('One follower');
134 str = ''+count+' '+_t('followers');
138 /* Display generic info about follower, for people not having access to res_partner */
139 display_generic: function () {
141 var node_user_list = this.$('.oe_follower_list').empty();
142 this.$('.oe_follower_title').html(this._format_followers(this.value.length));
145 /** Display the followers */
146 display_followers: function (records) {
148 records = records || [];
149 this.message_is_follower = this.set_is_follower(records);
150 // clean and display title
151 var node_user_list = this.$('.oe_follower_list').empty();
152 this.$('.oe_follower_title').html(this._format_followers(records.length));
153 // truncate number of displayed followers
154 truncated = records.splice(0, this.displayed_nb);
155 _(truncated).each(function (record) {
156 record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id);
157 $(session.web.qweb.render('mail.followers.partner', {'record': record})).appendTo(node_user_list);
159 // FVA note: be sure it is correctly translated
160 if (truncated.length < records.length) {
161 $('<div class="oe_partner">And ' + (records.length - truncated.length) + ' more.</div>').appendTo(node_user_list);
165 /** Computes whether the current user is in the followers */
166 set_is_follower: function (records) {
167 var user_ids = _.pluck(_.pluck(records, 'user_ids'), 0);
168 return _.indexOf(user_ids, this.session.uid) != -1;
171 display_buttons: function () {
172 if (this.message_is_follower) {
173 this.$('button.oe_follower').removeClass('oe_notfollow').addClass('oe_following');
176 this.$('button.oe_follower').removeClass('oe_following').addClass('oe_notfollow');
179 if (this.view.is_action_enabled('edit'))
180 this.$('span.oe_mail_invite_wrapper').hide();
182 this.$('span.oe_mail_invite_wrapper').show();
185 /** Fetch subtypes, only if current user is follower */
186 fetch_subtypes: function () {
187 var subtype_list_ul = this.$('.oe_subtype_list').empty();
188 if (! this.message_is_follower) return;
189 var context = new session.web.CompoundContext(this.build_context(), {});
190 this.ds_model.call('message_get_subscription_data', [[this.view.datarecord.id], context]).then(this.proxy('display_subtypes'));
193 /** Display subtypes: {'name': default, followed} */
194 display_subtypes:function (data) {
196 var subtype_list_ul = this.$('.oe_subtype_list');
197 subtype_list_ul.empty();
198 var records = data[this.view.datarecord.id || this.view.dataset.ids[0]].message_subtype_data;
199 if (records.length > 1) {
200 _(records).each(function (record, record_name) {
201 record.name = record_name;
202 record.followed = record.followed || undefined;
203 $(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo( self.$('.oe_subtype_list') );
208 do_follow: function () {
209 var context = new session.web.CompoundContext(this.build_context(), {});
210 this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], undefined, context])
211 .then(this.proxy('read_value'));
213 _.each(this.$('.oe_subtype_list input'), function (record) {
215 $(record).attr('checked', 'checked');
219 do_unfollow: function () {
220 _(this.$('.oe_msg_subtype_check')).each(function (record) {
221 $(record).attr('checked',false);
223 var context = new session.web.CompoundContext(this.build_context(), {});
224 return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context])
225 .then(this.proxy('read_value'));
228 do_update_subscription: function (event) {
231 var checklist = new Array();
232 _(this.$('.oe_actions input[type="checkbox"]')).each(function (record) {
233 if ($(record).is(':checked')) {
234 checklist.push(parseInt($(record).data('id')));
238 if (!checklist.length) {
241 var context = new session.web.CompoundContext(this.build_context(), {});
242 return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], checklist, context])
243 .then(this.proxy('read_value'));