Commit | Line | Data |
---|---|---|
50ac472f | 1 | _kiwi.view.Channel = _kiwi.view.Panel.extend({ |
9b807765 | 2 | events: function(){ |
c794b877 | 3 | var parent_events = this.constructor.__super__.events; |
3499d625 | 4 | |
9b807765 D |
5 | if(_.isFunction(parent_events)){ |
6 | parent_events = parent_events(); | |
7 | } | |
8 | return _.extend({}, parent_events, { | |
3499d625 D |
9 | 'click .msg .nick' : 'nickClick', |
10 | "click .chan": "chanClick", | |
11 | 'click .media .open': 'mediaClick', | |
12 | 'mouseenter .msg .nick': 'msgEnter', | |
13 | 'mouseleave .msg .nick': 'msgLeave' | |
9b807765 | 14 | }); |
dfb5209c JA |
15 | }, |
16 | ||
50ac472f D |
17 | initialize: function (options) { |
18 | this.initializePanel(options); | |
c794b877 D |
19 | |
20 | // Container for all the messages | |
21 | this.$messages = $('<div class="messages"></div>'); | |
22 | this.$el.append(this.$messages); | |
23 | ||
50ac472f D |
24 | this.model.bind('change:topic', this.topic, this); |
25 | ||
7d2a2771 D |
26 | if (this.model.get('members')) { |
27 | this.model.get('members').bind('add', function (member) { | |
28 | if (member.get('nick') === this.model.collection.network.get('nick')) { | |
29 | this.$el.find('.initial_loader').slideUp(function () { | |
30 | $(this).remove(); | |
31 | }); | |
32 | } | |
33 | }, this); | |
34 | } | |
660e1427 | 35 | |
50ac472f D |
36 | // Only show the loader if this is a channel (ie. not a query) |
37 | if (this.model.isChannel()) { | |
247dd7ac | 38 | this.$el.append('<div class="initial_loader" style="margin:1em;text-align:center;"> ' + _kiwi.global.i18n.translate('client_views_channel_joining').fetch() + ' <span class="loader"></span></div>'); |
50ac472f | 39 | } |
c794b877 D |
40 | |
41 | this.model.bind('msg', this.newMsg, this); | |
42 | this.msg_count = 0; | |
50ac472f D |
43 | }, |
44 | ||
c794b877 | 45 | |
41a9c836 D |
46 | render: function () { |
47 | var that = this; | |
48 | ||
49 | this.$messages.empty(); | |
50 | _.each(this.model.get('scrollback'), function (msg) { | |
51 | that.newMsg(msg); | |
52 | }); | |
53 | }, | |
54 | ||
55 | ||
c794b877 D |
56 | newMsg: function (msg) { |
57 | var re, line_msg, | |
58 | nick_colour_hex, nick_hex, is_highlight, msg_css_classes = '', | |
59 | time_difference, | |
60 | sb = this.model.get('scrollback'), | |
425efe7a | 61 | prev_msg = sb[sb.length-2], |
e9c86682 | 62 | network, hour, pm; |
c794b877 D |
63 | |
64 | // Nick highlight detecting | |
86f7df86 | 65 | var nick = _kiwi.app.connections.active_connection.get('nick'); |
66 | if ((new RegExp('(^|\\W)(' + escapeRegex(nick) + ')(\\W|$)', 'i')).test(msg.msg)) { | |
67 | // Do not highlight the user's own input | |
68 | if (msg.nick.localeCompare(nick) !== 0) { | |
69 | is_highlight = true; | |
70 | msg_css_classes += ' highlight'; | |
71 | } | |
c794b877 D |
72 | } |
73 | ||
74 | // Escape any HTML that may be in here | |
75 | msg.msg = $('<div />').text(msg.msg).html(); | |
76 | ||
77 | // Make the channels clickable | |
425efe7a | 78 | if ((network = this.model.get('network'))) { |
6547f118 CC |
79 | re = new RegExp('(^|\\s)([' + escapeRegex(network.get('channel_prefix')) + '][^ ,\\007]+)', 'g'); |
80 | msg.msg = msg.msg.replace(re, function (m1, m2) { | |
81 | return m2 + '<a class="chan" data-channel="' + _.escape(m1.trim()) + '">' + _.escape(m1.trim()) + '</a>'; | |
425efe7a JA |
82 | }); |
83 | } | |
c794b877 D |
84 | |
85 | ||
86 | // Parse any links found | |
87 | msg.msg = msg.msg.replace(/(([A-Za-z][A-Za-z0-9\-]*\:\/\/)|(www\.))([\w.\-]+)([a-zA-Z]{2,6})(:[0-9]+)?(\/[\w#!:.?$'()[\]*,;~+=&%@!\-\/]*)?/gi, function (url) { | |
88 | var nice = url, | |
89 | extra_html = ''; | |
90 | ||
c67de46d P |
91 | if (url.match(/^javascript:/)) { |
92 | return url; | |
93 | } | |
94 | ||
c794b877 D |
95 | // Add the http if no protoocol was found |
96 | if (url.match(/^www\./)) { | |
97 | url = 'http://' + url; | |
98 | } | |
99 | ||
100 | // Shorten the displayed URL if it's going to be too long | |
101 | if (nice.length > 100) { | |
102 | nice = nice.substr(0, 100) + '...'; | |
103 | } | |
104 | ||
105 | // Get any media HTML if supported | |
106 | extra_html = _kiwi.view.MediaMessage.buildHtml(url); | |
107 | ||
108 | // Make the link clickable | |
109 | return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url + '">' + nice + '</a>' + extra_html; | |
110 | }); | |
111 | ||
112 | ||
113 | // Convert IRC formatting into HTML formatting | |
114 | msg.msg = formatIRCMsg(msg.msg); | |
115 | ||
2eacc942 JA |
116 | // Replace text emoticons with images |
117 | if (_kiwi.global.settings.get('show_emoticons')) { | |
118 | msg.msg = emoticonFromText(msg.msg); | |
119 | } | |
c794b877 D |
120 | |
121 | // Add some colours to the nick (Method based on IRSSIs nickcolor.pl) | |
122 | nick_colour_hex = (function (nick) { | |
123 | var nick_int = 0, rgb; | |
124 | ||
125 | _.map(nick.split(''), function (i) { nick_int += i.charCodeAt(0); }); | |
126 | rgb = hsl2rgb(nick_int % 255, 70, 35); | |
127 | rgb = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16); | |
128 | ||
129 | return '#' + rgb.toString(16); | |
130 | })(msg.nick); | |
131 | ||
132 | msg.nick_style = 'color:' + nick_colour_hex + ';'; | |
133 | ||
134 | // Generate a hex string from the nick to be used as a CSS class name | |
135 | nick_hex = msg.nick_css_class = ''; | |
136 | if (msg.nick) { | |
137 | _.map(msg.nick.split(''), function (char) { | |
138 | nick_hex += char.charCodeAt(0).toString(16); | |
139 | }); | |
140 | msg_css_classes += ' nick_' + nick_hex; | |
141 | } | |
142 | ||
143 | if (prev_msg) { | |
144 | // Time difference between this message and the last (in minutes) | |
697a76c5 | 145 | time_difference = (msg.time.getTime() - prev_msg.time.getTime())/1000/60; |
c794b877 D |
146 | if (prev_msg.nick === msg.nick && time_difference < 1) { |
147 | msg_css_classes += ' repeated_nick'; | |
148 | } | |
149 | } | |
150 | ||
151 | // Build up and add the line | |
152 | msg.msg_css_classes = msg_css_classes; | |
62d1e896 JA |
153 | if (_kiwi.global.settings.get('use_24_hour_timestamps')) { |
154 | msg.time_string = msg.time.getHours().toString().lpad(2, "0") + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0"); | |
155 | } else { | |
156 | hour = msg.time.getHours(); | |
157 | pm = hour > 11; | |
36fb5f87 D |
158 | |
159 | hour = hour % 12; | |
160 | if (hour === 0) | |
161 | hour = 12; | |
162 | ||
62d1e896 JA |
163 | if (pm) { |
164 | msg.time_string = _kiwi.global.i18n.translate('client_views_panel_timestamp_pm').fetch(hour + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0")); | |
165 | } else { | |
166 | msg.time_string = _kiwi.global.i18n.translate('client_views_panel_timestamp_am').fetch(hour + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0")); | |
167 | } | |
168 | } | |
c794b877 | 169 | |
c1c51f22 D |
170 | _kiwi.global.events.emit('message:display', {panel: this.model, message: msg}) |
171 | .done(_.bind(function() { | |
172 | line_msg = '<div class="msg <%= type %> <%= msg_css_classes %>"><div class="time"><%- time_string %></div><div class="nick" style="<%= nick_style %>"><%- nick %></div><div class="text" style="<%= style %>"><%= msg %> </div></div>'; | |
173 | this.$messages.append(_.template(line_msg, msg)); | |
c794b877 | 174 | |
c1c51f22 D |
175 | // Activity/alerts based on the type of new message |
176 | if (msg.type.match(/^action /)) { | |
177 | this.alert('action'); | |
c794b877 | 178 | |
c1c51f22 | 179 | } else if (is_highlight) { |
c794b877 | 180 | _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch()); |
c1c51f22 D |
181 | _kiwi.app.view.favicon.newHighlight(); |
182 | _kiwi.app.view.playSound('highlight'); | |
183 | _kiwi.app.view.showNotification(this.model.get('name'), msg.msg); | |
184 | this.alert('highlight'); | |
185 | ||
186 | } else { | |
187 | // If this is the active panel, send an alert out | |
188 | if (this.model.isActive()) { | |
189 | _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch()); | |
190 | } | |
191 | this.alert('activity'); | |
c794b877 | 192 | } |
c794b877 | 193 | |
c1c51f22 D |
194 | if (this.model.isQuery() && !this.model.isActive()) { |
195 | _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch()); | |
ee2f0962 | 196 | |
c1c51f22 D |
197 | // Highlights have already been dealt with above |
198 | if (!is_highlight) { | |
199 | _kiwi.app.view.favicon.newHighlight(); | |
200 | } | |
ee2f0962 | 201 | |
c1c51f22 D |
202 | _kiwi.app.view.showNotification(this.model.get('name'), msg.msg); |
203 | _kiwi.app.view.playSound('highlight'); | |
204 | } | |
c794b877 | 205 | |
c1c51f22 D |
206 | // Update the activity counters |
207 | (function () { | |
208 | // Only inrement the counters if we're not the active panel | |
209 | if (this.model.isActive()) return; | |
c794b877 | 210 | |
c1c51f22 D |
211 | var $act = this.model.tab.find('.activity'), |
212 | count_all_activity = _kiwi.global.settings.get('count_all_activity'), | |
213 | exclude_message_types; | |
7ba064d9 | 214 | |
c1c51f22 D |
215 | // Set the default config value |
216 | if (typeof count_all_activity === 'undefined') { | |
217 | count_all_activity = false; | |
218 | } | |
223d53e5 | 219 | |
c1c51f22 D |
220 | // Do not increment the counter for these message types |
221 | exclude_message_types = [ | |
222 | 'action join', | |
223 | 'action quit', | |
224 | 'action part', | |
225 | 'action kick', | |
226 | 'action nick', | |
227 | 'action mode' | |
228 | ]; | |
229 | ||
230 | if (count_all_activity || _.indexOf(exclude_message_types, msg.type) === -1) { | |
231 | $act.text((parseInt($act.text(), 10) || 0) + 1); | |
232 | } | |
223d53e5 | 233 | |
c1c51f22 D |
234 | if ($act.text() === '0') { |
235 | $act.addClass('zero'); | |
236 | } else { | |
237 | $act.removeClass('zero'); | |
238 | } | |
239 | }).apply(this); | |
c794b877 | 240 | |
c1c51f22 | 241 | if(this.model.isActive()) this.scrollToBottom(); |
c794b877 | 242 | |
c1c51f22 D |
243 | // Make sure our DOM isn't getting too large (Acts as scrollback) |
244 | this.msg_count++; | |
245 | if (this.msg_count > (parseInt(_kiwi.global.settings.get('scrollback'), 10) || 250)) { | |
246 | $('.msg:first', this.$messages).remove(); | |
247 | this.msg_count--; | |
248 | } | |
249 | }, this)); | |
50ac472f D |
250 | }, |
251 | ||
c794b877 | 252 | |
50ac472f D |
253 | topic: function (topic) { |
254 | if (typeof topic !== 'string' || !topic) { | |
255 | topic = this.model.get("topic"); | |
256 | } | |
257 | ||
9ec48c54 | 258 | this.model.addMsg('', styleText('channel_topic', {text: translateText('client_views_channel_topic', [this.model.get('name'), topic]), channel: this.model.get('name')}), 'topic'); |
50ac472f D |
259 | |
260 | // If this is the active channel then update the topic bar | |
261 | if (_kiwi.app.panels().active === this) { | |
262 | _kiwi.app.topicbar.setCurrentTopic(this.model.get("topic")); | |
263 | } | |
dfb5209c JA |
264 | }, |
265 | ||
266 | // Click on a nickname | |
267 | nickClick: function (event) { | |
268 | var nick = $(event.currentTarget).text(), | |
269 | members = this.model.get('members'), | |
d62fa271 | 270 | are_we_an_op = !!members.getByNick(_kiwi.app.connections.active_connection.get('nick')).get('is_op'), |
dfb5209c JA |
271 | member, query, userbox, menubox; |
272 | ||
273 | if (members) { | |
274 | member = members.getByNick(nick); | |
275 | if (member) { | |
dfb5209c | 276 | userbox = new _kiwi.view.UserBox(); |
d62fa271 D |
277 | userbox.setTargets(member, this.model); |
278 | userbox.displayOpItems(are_we_an_op); | |
0826460d | 279 | |
dfb5209c JA |
280 | menubox = new _kiwi.view.MenuBox(member.get('nick') || 'User'); |
281 | menubox.addItem('userbox', userbox.$el); | |
279bf34b | 282 | menubox.showFooter(false); |
dfb5209c | 283 | menubox.show(); |
0826460d | 284 | |
dfb5209c JA |
285 | // Position the userbox + menubox |
286 | (function() { | |
287 | var t = event.pageY, | |
288 | m_bottom = t + menubox.$el.outerHeight(), // Where the bottom of menu will be | |
289 | memberlist_bottom = this.$el.parent().offset().top + this.$el.parent().outerHeight(); | |
290 | ||
291 | // If the bottom of the userbox is going to be too low.. raise it | |
292 | if (m_bottom > memberlist_bottom){ | |
293 | t = memberlist_bottom - menubox.$el.outerHeight(); | |
294 | } | |
295 | ||
296 | // Set the new positon | |
297 | menubox.$el.offset({ | |
298 | left: event.clientX, | |
299 | top: t | |
300 | }); | |
301 | }).call(this); | |
302 | } | |
303 | } | |
3499d625 D |
304 | }, |
305 | ||
306 | ||
307 | chanClick: function (event) { | |
425efe7a JA |
308 | var target = (event.target) ? $(event.target).data('channel') : $(event.srcElement).data('channel'); |
309 | ||
310 | _kiwi.app.connections.active_connection.gateway.join(target); | |
3499d625 D |
311 | }, |
312 | ||
313 | ||
314 | mediaClick: function (event) { | |
315 | var $media = $(event.target).parents('.media'); | |
316 | var media_message; | |
317 | ||
318 | if ($media.data('media')) { | |
319 | media_message = $media.data('media'); | |
320 | } else { | |
321 | media_message = new _kiwi.view.MediaMessage({el: $media[0]}); | |
322 | ||
323 | // Cache this MediaMessage instance for when it's opened again | |
324 | $media.data('media', media_message); | |
325 | } | |
326 | ||
327 | media_message.toggle(); | |
328 | }, | |
329 | ||
330 | ||
331 | // Cursor hovers over a message | |
332 | msgEnter: function (event) { | |
333 | var nick_class; | |
334 | ||
335 | // Find a valid class that this element has | |
336 | _.each($(event.currentTarget).parent('.msg').attr('class').split(' '), function (css_class) { | |
337 | if (css_class.match(/^nick_[a-z0-9]+/i)) { | |
338 | nick_class = css_class; | |
339 | } | |
340 | }); | |
341 | ||
342 | // If no class was found.. | |
343 | if (!nick_class) return; | |
344 | ||
345 | $('.'+nick_class).addClass('global_nick_highlight'); | |
346 | }, | |
347 | ||
348 | ||
349 | // Cursor leaves message | |
350 | msgLeave: function (event) { | |
351 | var nick_class; | |
352 | ||
353 | // Find a valid class that this element has | |
354 | _.each($(event.currentTarget).parent('.msg').attr('class').split(' '), function (css_class) { | |
355 | if (css_class.match(/^nick_[a-z0-9]+/i)) { | |
356 | nick_class = css_class; | |
357 | } | |
358 | }); | |
359 | ||
360 | // If no class was found.. | |
361 | if (!nick_class) return; | |
362 | ||
363 | $('.'+nick_class).removeClass('global_nick_highlight'); | |
364 | }, | |
dfb5209c | 365 | }); |