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 | ||
72a325ec | 56 | newMsg: function(msg) { |
c794b877 | 57 | |
72a325ec D |
58 | // Parse the msg object into properties fit for displaying |
59 | msg = this.generateMessageDisplayObj(msg); | |
c794b877 | 60 | |
c1c51f22 D |
61 | _kiwi.global.events.emit('message:display', {panel: this.model, message: msg}) |
62 | .done(_.bind(function() { | |
72a325ec D |
63 | var line_msg; |
64 | ||
e8885df9 D |
65 | // Format the nick to the config defined format |
66 | var display_obj = _.clone(msg); | |
67 | display_obj.nick = styleText('message_nick', {nick: msg.nick, prefix: msg.nick_prefix || ''}); | |
68 | ||
72a325ec | 69 | line_msg = '<div class="msg <%= type %> <%= css_classes %>"><div class="time"><%- time_string %></div><div class="nick" style="<%= nick_style %>"><%- nick %></div><div class="text" style="<%= style %>"><%= msg %> </div></div>'; |
e8885df9 | 70 | this.$messages.append($(_.template(line_msg, display_obj)).data('message', msg)); |
c794b877 | 71 | |
c1c51f22 D |
72 | // Activity/alerts based on the type of new message |
73 | if (msg.type.match(/^action /)) { | |
74 | this.alert('action'); | |
c794b877 | 75 | |
72a325ec | 76 | } else if (msg.is_highlight) { |
c794b877 | 77 | _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch()); |
c1c51f22 D |
78 | _kiwi.app.view.favicon.newHighlight(); |
79 | _kiwi.app.view.playSound('highlight'); | |
80 | _kiwi.app.view.showNotification(this.model.get('name'), msg.msg); | |
81 | this.alert('highlight'); | |
82 | ||
83 | } else { | |
84 | // If this is the active panel, send an alert out | |
85 | if (this.model.isActive()) { | |
86 | _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch()); | |
87 | } | |
88 | this.alert('activity'); | |
c794b877 | 89 | } |
c794b877 | 90 | |
c1c51f22 D |
91 | if (this.model.isQuery() && !this.model.isActive()) { |
92 | _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch()); | |
ee2f0962 | 93 | |
c1c51f22 | 94 | // Highlights have already been dealt with above |
72a325ec | 95 | if (!msg.is_highlight) { |
c1c51f22 D |
96 | _kiwi.app.view.favicon.newHighlight(); |
97 | } | |
ee2f0962 | 98 | |
c1c51f22 D |
99 | _kiwi.app.view.showNotification(this.model.get('name'), msg.msg); |
100 | _kiwi.app.view.playSound('highlight'); | |
101 | } | |
c794b877 | 102 | |
c1c51f22 D |
103 | // Update the activity counters |
104 | (function () { | |
105 | // Only inrement the counters if we're not the active panel | |
106 | if (this.model.isActive()) return; | |
c794b877 | 107 | |
c1c51f22 D |
108 | var $act = this.model.tab.find('.activity'), |
109 | count_all_activity = _kiwi.global.settings.get('count_all_activity'), | |
110 | exclude_message_types; | |
7ba064d9 | 111 | |
c1c51f22 D |
112 | // Set the default config value |
113 | if (typeof count_all_activity === 'undefined') { | |
114 | count_all_activity = false; | |
115 | } | |
223d53e5 | 116 | |
c1c51f22 D |
117 | // Do not increment the counter for these message types |
118 | exclude_message_types = [ | |
119 | 'action join', | |
120 | 'action quit', | |
121 | 'action part', | |
122 | 'action kick', | |
123 | 'action nick', | |
124 | 'action mode' | |
125 | ]; | |
126 | ||
127 | if (count_all_activity || _.indexOf(exclude_message_types, msg.type) === -1) { | |
128 | $act.text((parseInt($act.text(), 10) || 0) + 1); | |
129 | } | |
223d53e5 | 130 | |
c1c51f22 D |
131 | if ($act.text() === '0') { |
132 | $act.addClass('zero'); | |
133 | } else { | |
134 | $act.removeClass('zero'); | |
135 | } | |
136 | }).apply(this); | |
c794b877 | 137 | |
c1c51f22 | 138 | if(this.model.isActive()) this.scrollToBottom(); |
c794b877 | 139 | |
c1c51f22 D |
140 | // Make sure our DOM isn't getting too large (Acts as scrollback) |
141 | this.msg_count++; | |
142 | if (this.msg_count > (parseInt(_kiwi.global.settings.get('scrollback'), 10) || 250)) { | |
143 | $('.msg:first', this.$messages).remove(); | |
144 | this.msg_count--; | |
145 | } | |
146 | }, this)); | |
50ac472f D |
147 | }, |
148 | ||
c794b877 | 149 | |
72a325ec D |
150 | // Make channels clickable |
151 | parseMessageChannels: function(word) { | |
152 | var re, | |
153 | parsed = false, | |
154 | network = this.model.get('network'); | |
155 | ||
156 | if (!network) { | |
157 | return; | |
158 | } | |
159 | ||
160 | re = new RegExp('(^|\\s)([' + escapeRegex(network.get('channel_prefix')) + '][^ ,\\007]+)', 'g'); | |
161 | ||
162 | if (!word.match(re)) { | |
163 | return parsed; | |
164 | } | |
165 | ||
166 | parsed = word.replace(re, function (m1, m2) { | |
167 | return m2 + '<a class="chan" data-channel="' + _.escape(m1.trim()) + '">' + _.escape(m1.trim()) + '</a>'; | |
168 | }); | |
169 | ||
170 | return parsed; | |
171 | }, | |
172 | ||
173 | ||
174 | parseMessageUrls: function(word) { | |
175 | var found_a_url = false, | |
176 | parsed_url; | |
177 | ||
178 | parsed_url = word.replace(/(([A-Za-z][A-Za-z0-9\-]*\:\/\/)|(www\.))([\w.\-]+)([a-zA-Z]{2,6})(:[0-9]+)?(\/[\w#!:.?$'()[\]*,;~+=&%@!\-\/]*)?/gi, function (url) { | |
179 | var nice = url, | |
180 | extra_html = ''; | |
181 | ||
182 | // Don't allow javascript execution | |
183 | if (url.match(/^javascript:/)) { | |
184 | return url; | |
185 | } | |
186 | ||
187 | found_a_url = true; | |
188 | ||
189 | // Add the http if no protoocol was found | |
190 | if (url.match(/^www\./)) { | |
191 | url = 'http://' + url; | |
192 | } | |
193 | ||
194 | // Shorten the displayed URL if it's going to be too long | |
195 | if (nice.length > 100) { | |
196 | nice = nice.substr(0, 100) + '...'; | |
197 | } | |
198 | ||
199 | // Get any media HTML if supported | |
200 | extra_html = _kiwi.view.MediaMessage.buildHtml(url); | |
201 | ||
202 | // Make the link clickable | |
203 | return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url + '">' + nice + '</a>' + extra_html; | |
204 | }); | |
205 | ||
206 | return found_a_url ? parsed_url : false; | |
207 | }, | |
208 | ||
209 | ||
210 | // Get a colour from a nick (Method based on IRSSIs nickcolor.pl) | |
211 | getNickColour: function(nick) { | |
212 | var nick_int = 0, rgb; | |
213 | ||
214 | _.map(nick.split(''), function (i) { nick_int += i.charCodeAt(0); }); | |
215 | rgb = hsl2rgb(nick_int % 255, 70, 35); | |
216 | rgb = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16); | |
217 | ||
218 | return '#' + rgb.toString(16); | |
219 | }, | |
220 | ||
221 | ||
222 | // Takes an IRC message object and parses it for displaying | |
223 | generateMessageDisplayObj: function(msg) { | |
224 | var nick_hex, time_difference, | |
225 | message_words, | |
226 | sb = this.model.get('scrollback'), | |
227 | prev_msg = sb[sb.length-2], | |
228 | hour, pm, am_pm_locale_key; | |
229 | ||
230 | // Clone the msg object so we dont modify the original | |
231 | msg = _.clone(msg); | |
232 | ||
233 | // Defaults | |
234 | msg.css_classes = ''; | |
235 | msg.nick_style = ''; | |
236 | msg.is_highlight = false; | |
237 | msg.time_string = ''; | |
238 | ||
239 | ||
240 | // Nick highlight detecting | |
241 | var nick = _kiwi.app.connections.active_connection.get('nick'); | |
242 | if ((new RegExp('(^|\\W)(' + escapeRegex(nick) + ')(\\W|$)', 'i')).test(msg.msg)) { | |
243 | // Do not highlight the user's own input | |
244 | if (msg.nick.localeCompare(nick) !== 0) { | |
245 | msg.is_highlight = true; | |
246 | msg.css_classes += ' highlight'; | |
247 | } | |
248 | } | |
249 | ||
250 | message_words = msg.msg.split(' '); | |
251 | message_words = _.map(message_words, function(word) { | |
252 | var parsed_word; | |
253 | ||
254 | parsed_word = this.parseMessageUrls(word); | |
255 | if (typeof parsed_word === 'string') return parsed_word; | |
256 | ||
257 | parsed_word = this.parseMessageChannels(word); | |
258 | if (typeof parsed_word === 'string') return parsed_word; | |
259 | ||
260 | parsed_word = _.escape(word); | |
261 | ||
262 | // Replace text emoticons with images | |
263 | if (_kiwi.global.settings.get('show_emoticons')) { | |
264 | parsed_word = emoticonFromText(parsed_word); | |
265 | } | |
266 | ||
267 | return parsed_word; | |
268 | }, this); | |
269 | ||
270 | msg.msg = message_words.join(' '); | |
271 | ||
272 | // Convert IRC formatting into HTML formatting | |
273 | msg.msg = formatIRCMsg(msg.msg); | |
274 | ||
275 | // Add some colours to the nick | |
276 | msg.nick_style = 'color:' + this.getNickColour(msg.nick) + ';'; | |
277 | ||
278 | // Generate a hex string from the nick to be used as a CSS class name | |
279 | nick_hex = ''; | |
280 | if (msg.nick) { | |
281 | _.map(msg.nick.split(''), function (char) { | |
282 | nick_hex += char.charCodeAt(0).toString(16); | |
283 | }); | |
284 | msg.css_classes += ' nick_' + nick_hex; | |
285 | } | |
286 | ||
287 | if (prev_msg) { | |
288 | // Time difference between this message and the last (in minutes) | |
289 | time_difference = (msg.time.getTime() - prev_msg.time.getTime())/1000/60; | |
290 | if (prev_msg.nick === msg.nick && time_difference < 1) { | |
291 | msg.css_classes += ' repeated_nick'; | |
292 | } | |
293 | } | |
294 | ||
295 | // Build up and add the line | |
296 | if (_kiwi.global.settings.get('use_24_hour_timestamps')) { | |
297 | msg.time_string = msg.time.getHours().toString().lpad(2, "0") + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0"); | |
298 | } else { | |
299 | hour = msg.time.getHours(); | |
300 | pm = hour > 11; | |
301 | ||
302 | hour = hour % 12; | |
303 | if (hour === 0) | |
304 | hour = 12; | |
305 | ||
306 | am_pm_locale_key = pm ? | |
307 | 'client_views_panel_timestamp_pm' : | |
308 | 'client_views_panel_timestamp_am'; | |
309 | ||
310 | msg.time_string = translateText(am_pm_locale_key, hour + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0")); | |
311 | } | |
312 | ||
313 | return msg; | |
314 | }, | |
315 | ||
316 | ||
50ac472f D |
317 | topic: function (topic) { |
318 | if (typeof topic !== 'string' || !topic) { | |
319 | topic = this.model.get("topic"); | |
320 | } | |
321 | ||
9a10cede | 322 | this.model.addMsg('', styleText('channel_topic', {text: topic, channel: this.model.get('name')}), 'topic'); |
50ac472f D |
323 | |
324 | // If this is the active channel then update the topic bar | |
325 | if (_kiwi.app.panels().active === this) { | |
326 | _kiwi.app.topicbar.setCurrentTopic(this.model.get("topic")); | |
327 | } | |
dfb5209c JA |
328 | }, |
329 | ||
330 | // Click on a nickname | |
331 | nickClick: function (event) { | |
e8885df9 | 332 | var nick = $(event.currentTarget).parent('.msg').data('message').nick, |
dfb5209c | 333 | members = this.model.get('members'), |
d62fa271 | 334 | are_we_an_op = !!members.getByNick(_kiwi.app.connections.active_connection.get('nick')).get('is_op'), |
dfb5209c JA |
335 | member, query, userbox, menubox; |
336 | ||
337 | if (members) { | |
338 | member = members.getByNick(nick); | |
339 | if (member) { | |
dfb5209c | 340 | userbox = new _kiwi.view.UserBox(); |
d62fa271 D |
341 | userbox.setTargets(member, this.model); |
342 | userbox.displayOpItems(are_we_an_op); | |
0826460d | 343 | |
dfb5209c JA |
344 | menubox = new _kiwi.view.MenuBox(member.get('nick') || 'User'); |
345 | menubox.addItem('userbox', userbox.$el); | |
279bf34b | 346 | menubox.showFooter(false); |
dfb5209c | 347 | menubox.show(); |
0826460d | 348 | |
dfb5209c JA |
349 | // Position the userbox + menubox |
350 | (function() { | |
351 | var t = event.pageY, | |
352 | m_bottom = t + menubox.$el.outerHeight(), // Where the bottom of menu will be | |
353 | memberlist_bottom = this.$el.parent().offset().top + this.$el.parent().outerHeight(); | |
354 | ||
355 | // If the bottom of the userbox is going to be too low.. raise it | |
356 | if (m_bottom > memberlist_bottom){ | |
357 | t = memberlist_bottom - menubox.$el.outerHeight(); | |
358 | } | |
359 | ||
360 | // Set the new positon | |
361 | menubox.$el.offset({ | |
362 | left: event.clientX, | |
363 | top: t | |
364 | }); | |
365 | }).call(this); | |
366 | } | |
367 | } | |
3499d625 D |
368 | }, |
369 | ||
370 | ||
371 | chanClick: function (event) { | |
425efe7a JA |
372 | var target = (event.target) ? $(event.target).data('channel') : $(event.srcElement).data('channel'); |
373 | ||
374 | _kiwi.app.connections.active_connection.gateway.join(target); | |
3499d625 D |
375 | }, |
376 | ||
377 | ||
378 | mediaClick: function (event) { | |
379 | var $media = $(event.target).parents('.media'); | |
380 | var media_message; | |
381 | ||
382 | if ($media.data('media')) { | |
383 | media_message = $media.data('media'); | |
384 | } else { | |
385 | media_message = new _kiwi.view.MediaMessage({el: $media[0]}); | |
386 | ||
387 | // Cache this MediaMessage instance for when it's opened again | |
388 | $media.data('media', media_message); | |
389 | } | |
390 | ||
391 | media_message.toggle(); | |
392 | }, | |
393 | ||
394 | ||
395 | // Cursor hovers over a message | |
396 | msgEnter: function (event) { | |
397 | var nick_class; | |
398 | ||
399 | // Find a valid class that this element has | |
400 | _.each($(event.currentTarget).parent('.msg').attr('class').split(' '), function (css_class) { | |
401 | if (css_class.match(/^nick_[a-z0-9]+/i)) { | |
402 | nick_class = css_class; | |
403 | } | |
404 | }); | |
405 | ||
406 | // If no class was found.. | |
407 | if (!nick_class) return; | |
408 | ||
409 | $('.'+nick_class).addClass('global_nick_highlight'); | |
410 | }, | |
411 | ||
412 | ||
413 | // Cursor leaves message | |
414 | msgLeave: function (event) { | |
415 | var nick_class; | |
416 | ||
417 | // Find a valid class that this element has | |
418 | _.each($(event.currentTarget).parent('.msg').attr('class').split(' '), function (css_class) { | |
419 | if (css_class.match(/^nick_[a-z0-9]+/i)) { | |
420 | nick_class = css_class; | |
421 | } | |
422 | }); | |
423 | ||
424 | // If no class was found.. | |
425 | if (!nick_class) return; | |
426 | ||
427 | $('.'+nick_class).removeClass('global_nick_highlight'); | |
428 | }, | |
dfb5209c | 429 | }); |