Merge branch 'hotfix/21.56.9' into master
[gitter.git] / public / js / views / righttoolbar / activityCompositeView.js
blobafc7bcdfe624fa2dcfd091a9a469a7c0fb1df332
1 'use strict';
2 var _ = require('lodash');
3 var Marionette = require('backbone.marionette');
4 var classnames = require('classnames');
5 var appEvents = require('../../utils/appevents');
6 var issuableDecorator = require('../chat/decorators/issuableDecorator');
7 var commitDecorator = require('../chat/decorators/commitDecorator');
8 var mentionDecorator = require('../chat/decorators/mentionDecorator');
9 var debug = require('debug-proxy')('app:activity-composite-view');
10 var githubPushTemplate = require('./tmpl/githubPush.hbs');
11 var githubIssuesTemplate = require('./tmpl/githubIssues.hbs');
12 var githubIssueCommentTemplate = require('./tmpl/githubIssueComment.hbs');
13 var githubCommitCommentTemplate = require('./tmpl/githubCommitComment.hbs');
14 var githubPullRequestTemplate = require('./tmpl/githubPullRequest.hbs');
15 var githubGollumTemplate = require('./tmpl/githubGollum.hbs');
16 var githubForkTemplate = require('./tmpl/githubFork.hbs');
17 var githubMemberTemplate = require('./tmpl/githubMember.hbs');
18 var githubPublicTemplate = require('./tmpl/githubPublic.hbs');
19 var githubWatchTemplate = require('./tmpl/githubWatch.hbs');
20 var bitbucketTemplate = require('./tmpl/bitbucket.hbs');
21 var huboardTemplate = require('./tmpl/huboard.hbs');
22 var jenkinsTemplate = require('./tmpl/jenkins.hbs');
23 var travisTemplate = require('./tmpl/travis.hbs');
24 var sprintlyTemplate = require('./tmpl/sprintly.hbs');
25 var trelloTemplate = require('./tmpl/trello.hbs');
26 var prerenderedTemplate = require('./tmpl/activity-item-prerendered.hbs');
27 var activityTemplate = require('./tmpl/activity-composite.hbs');
28 var activityEmptyTemplate = require('./tmpl/activity-empty.hbs');
29 var activityDecorators = require('gitter-web-shared/activity/activity-decorators');
30 var context = require('gitter-web-client-context');
31 var clientEnv = require('gitter-client-env');
32 var timeFormat = require('gitter-web-shared/time/time-format');
33 var fullTimeFormat = require('gitter-web-shared/time/full-time-format');
34 var compositeViewRenderTemplate = require('../../utils/composite-view-render-template');
36 require('../behaviors/timeago');
37 require('../behaviors/tooltip');
39 module.exports = (function() {
40   var serviceTemplates = {
41     bitbucket: bitbucketTemplate,
42     huboard: huboardTemplate,
43     jenkins: jenkinsTemplate,
44     travis: travisTemplate,
45     sprintly: sprintlyTemplate,
46     trello: trelloTemplate
47   };
49   var githubTemplates = {
50     push: githubPushTemplate,
51     issues: githubIssuesTemplate,
52     issue_comment: githubIssueCommentTemplate,
53     commit_comment: githubCommitCommentTemplate,
54     pull_request: githubPullRequestTemplate,
55     gollum: githubGollumTemplate,
56     fork: githubForkTemplate,
57     member: githubMemberTemplate,
58     public: githubPublicTemplate,
59     watch: githubWatchTemplate
60   };
62   function getTemplateForModel(model) {
63     var meta = model.get('meta');
64     var service = meta.service;
66     if (service == 'github') {
67       var event = meta.event;
68       return githubTemplates[event];
69     }
71     if (meta.prerendered) {
72       return prerenderedTemplate;
73     }
75     return serviceTemplates[service];
76   }
78   var ActivityItemView = Marionette.ItemView.extend({
79     tagName: 'li',
80     attributes: function() {
81       var classMap = {
82         'activity-item': true
83       };
84       return {
85         class: classnames(classMap)
86       };
87     },
88     modelEvents: {
89       change: 'render'
90     },
91     behaviors: {
92       TimeAgo: {
93         modelAttribute: 'sent',
94         el: '#time'
95       },
96       Tooltip: {
97         '#time': {
98           titleFn: 'getTimeTooltip',
99           placement: 'left'
100         }
101       }
102     },
104     initialize: function() {
105       this.template = getTemplateForModel(this.model);
106     },
108     serializeData: function() {
109       try {
110         var meta = this.model.get('meta');
111         var payload = this.model.get('payload');
112         var sent = this.model.get('sent');
113         var html = this.model.get('html');
114         var sentFormatted = timeFormat(sent, { compact: true });
116         var core = {
117           meta: meta,
118           payload: payload,
119           sent: sent,
120           sentFormatted: sentFormatted,
121           html: html
122         };
124         var extra = meta.prerendered ? {} : activityDecorators(meta, payload);
125         var result = _.extend(core, extra);
126         return result;
127       } catch (e) {
128         var modelData = this.model && this.model.attributes;
129         appEvents.trigger('bugreport', e, { extra: modelData });
130         debug(
131           'Err rendering activity item: error=%s, stack=%s, data=%j',
132           e.message,
133           e.stack,
134           modelData
135         );
136         return {};
137       }
138     },
140     onRender: function() {
141       issuableDecorator.decorate(this);
142       commitDecorator.decorate(this);
143       mentionDecorator.decorate(this);
144     },
146     getTimeTooltip: function() {
147       var sent = this.model.get('sent');
148       return fullTimeFormat(sent);
149     }
150   });
152   var ActivityEmptyItemView = Marionette.ItemView.extend({
153     tagName: 'li',
154     className: 'activity-tip',
155     template: activityEmptyTemplate,
156     serializeData: function() {
157       var isNativeDesktopApp = context().isNativeDesktopApp;
158       var basePath = isNativeDesktopApp ? clientEnv['basePath'] + context.troupe().get('url') : '';
159       var integrationsUrl = basePath + '#integrations';
161       return {
162         integrationsUrl: integrationsUrl,
163         isNativeDesktopApp: isNativeDesktopApp
164       };
165     }
166   });
168   var ActivityView = Marionette.CompositeView.extend({
169     template: activityTemplate,
170     className: 'gtrActivityContainer',
171     childViewContainer: '#activity-list',
172     childView: ActivityItemView,
173     collectionEvents: {
174       'add reset sync reset loaded loading': '_showHideHeader',
175       reset: 'onCollectionReset'
176     },
177     childViewOptions: function(item) {
178       if (item && item.id) {
179         // This allows the chat collection view to bind to an existing element...
180         var e = this.$el.find('.model-id-' + item.id)[0];
181         if (e) return { el: e };
182       }
183     },
184     getEmptyView: function() {
185       // Admins see "Configure your integrations" empty
186       if (context.isTroupeAdmin()) return ActivityEmptyItemView;
187     },
188     ui: {
189       header: '#activity-header'
190     },
191     onCollectionReset: function() {
192       if (this.collection.length) return;
194       var el = this.$el.find(this.childViewContainer)[0];
195       if (!el) return;
197       var child;
198       while ((child = el.firstChild)) {
199         el.removeChild(child);
200       }
201     },
202     onRender: function() {
203       this._showHideHeader();
204     },
205     _showHideHeader: function() {
206       // Admins see the header when the collection is empty
207       // so that they get to
208       var viewReloading = this.collection.length === 0 && this.collection.loading;
209       this.$el.toggleClass('loading', viewReloading);
210       var headerVisible =
211         !context.inOneToOneTroupeContext() && !!(context.isTroupeAdmin() || this.collection.length);
212       this.ui.header.toggle(headerVisible);
213     },
215     _renderTemplate: compositeViewRenderTemplate
216   });
218   return ActivityView;
219 })();