var $this = $(this.el);\r
$this.empty();\r
this.model.forEach(function (member) {\r
- $('<li><a class="nick"><span class="prefix">' + member.get("prefix") + '</span>' + member.get("nick") + '</a></li>')\r
+ var prefix_css_class = (member.get('modes') || []).join(' ');\r
+ $('<li class="mode ' + prefix_css_class + '"><a class="nick"><span class="prefix">' + member.get("prefix") + '</span>' + member.get("nick") + '</a></li>')\r
.appendTo($this)\r
.data('member', member);\r
});\r
},\r
nickClick: function (x) {\r
- var target = $(x.currentTarget).parent('li'),\r
- member = target.data('member'),\r
- userbox = new _kiwi.view.UserBox();\r
+ var $target = $(x.currentTarget).parent('li'),\r
+ member = $target.data('member'),\r
+ userbox;\r
\r
+ // If the userbox already exists here, hide it\r
+ if ($target.find('.userbox').length > 0) {\r
+ $('.userbox', this.$el).remove();\r
+ return;\r
+ }\r
+\r
+ userbox = new _kiwi.view.UserBox();\r
userbox.member = member;\r
+\r
+ // Remove any existing userboxes\r
$('.userbox', this.$el).remove();\r
- target.append(userbox.$el);\r
+\r
+ $target.append(userbox.$el);\r
},\r
show: function () {\r
$('#memberlists').children().removeClass('active');\r
var model = Backbone.View.extend({\r
events: {\r
'submit form': 'submitForm',\r
- 'click .show_more': 'showMore'\r
+ 'click .show_more': 'showMore',\r
+ 'change .have_pass input': 'showPass'\r
},\r
\r
initialize: function () {\r
+ var that = this;\r
+\r
this.$el = $($('#tmpl_server_select').html());\r
\r
// Remove the 'more' link if the server has disabled server changing\r
this.setStatus('Nickname already taken');\r
this.show('nick_change');\r
}\r
+\r
+ if (data.error == 'password_mismatch') {\r
+ this.setStatus('Incorrect Password');\r
+ this.show('nick_change');\r
+ that.$el.find('.password').select();\r
+ }\r
}, this);\r
},\r
\r
submitForm: function (event) {\r
+ event.preventDefault();\r
+\r
+ // Make sure a nick is chosen\r
+ if (!$('input.nick', this.$el).val().trim()) {\r
+ this.setStatus('Select a nickname first!');\r
+ $('input.nick', this.$el).select();\r
+ return;\r
+ }\r
+\r
if (state === 'nick_change') {\r
this.submitNickChange(event);\r
} else {\r
}\r
\r
$('button', this.$el).attr('disabled', 1);\r
- return false;\r
+ return;\r
},\r
\r
submitLogin: function (event) {\r
if ($('button', this.$el).attr('disabled')) return;\r
\r
var values = {\r
- nick: $('.nick', this.$el).val(),\r
- server: $('.server', this.$el).val(),\r
- port: $('.port', this.$el).val(),\r
- ssl: $('.ssl', this.$el).prop('checked'),\r
- password: $('.password', this.$el).val(),\r
- channel: $('.channel', this.$el).val(),\r
- channel_key: $('.channel_key', this.$el).val()\r
+ nick: $('input.nick', this.$el).val(),\r
+ server: $('input.server', this.$el).val(),\r
+ port: $('input.port', this.$el).val(),\r
+ ssl: $('input.ssl', this.$el).prop('checked'),\r
+ password: $('input.password', this.$el).val(),\r
+ channel: $('input.channel', this.$el).val(),\r
+ channel_key: $('input.channel_key', this.$el).val()\r
};\r
\r
this.trigger('server_connect', values);\r
},\r
\r
submitNickChange: function (event) {\r
- _kiwi.gateway.changeNick($('.nick', this.$el).val());\r
+ _kiwi.gateway.changeNick($('input.nick', this.$el).val());\r
this.networkConnecting();\r
},\r
\r
+ showPass: function (event) {\r
+ if (this.$el.find('tr.have_pass input').is(':checked')) {\r
+ this.$el.find('tr.pass').show().find('input').focus();\r
+ } else {\r
+ this.$el.find('tr.pass').hide().find('input').val('');\r
+ }\r
+ },\r
+\r
showMore: function (event) {\r
$('.more', this.$el).slideDown('fast');\r
- $('.server', this.$el).select();\r
+ $('input.server', this.$el).select();\r
},\r
\r
populateFields: function (defaults) {\r
channel = defaults.channel || '';\r
channel_key = defaults.channel_key || '';\r
\r
- $('.nick', this.$el).val(nick);\r
- $('.server', this.$el).val(server);\r
- $('.port', this.$el).val(port);\r
- $('.ssl', this.$el).prop('checked', ssl);\r
- $('.password', this.$el).val(password);\r
- $('.channel', this.$el).val(channel);\r
- $('.channel_key', this.$el).val(channel_key);\r
+ $('input.nick', this.$el).val(nick);\r
+ $('input.server', this.$el).val(server);\r
+ $('input.port', this.$el).val(port);\r
+ $('input.ssl', this.$el).prop('checked', ssl);\r
+ $('input.password', this.$el).val(password);\r
+ $('input.channel', this.$el).val(channel);\r
+ $('input.channel_key', this.$el).val(channel_key);\r
},\r
\r
hide: function () {\r
} else if (new_state === 'nick_change') {\r
$('.more', this.$el).hide();\r
$('.show_more', this.$el).hide();\r
+ $('input.nick', this.$el).select();\r
}\r
\r
state = new_state;\r
$('.status', this.$el)\r
.text(text)\r
.attr('class', 'status')\r
- .addClass(class_name)\r
+ .addClass(class_name||'')\r
.show();\r
},\r
clearStatus: function () {\r
className: "messages",\r
events: {\r
"click .chan": "chanClick",\r
+ 'click .media .open': 'mediaClick',\r
'mouseenter .msg .nick': 'msgEnter',\r
'mouseleave .msg .nick': 'msgLeave'\r
},\r
},\r
\r
render: function () {\r
+ var that = this;\r
+\r
this.$el.empty();\r
- this.model.get("backscroll").forEach(this.newMsg);\r
+ _.each(this.model.get('scrollback'), function (msg) {\r
+ that.newMsg(msg);\r
+ });\r
},\r
+\r
newMsg: function (msg) {\r
- // TODO: make sure that the message pane is scrolled to the bottom (Or do we? ~Darren)\r
var re, line_msg, $this = this.$el,\r
nick_colour_hex, nick_hex, is_highlight, msg_css_classes = '';\r
\r
msg.msg = $('<div />').text(msg.msg).html();\r
\r
// Make the channels clickable\r
- re = new RegExp('\\B([' + _kiwi.gateway.get('channel_prefix') + '][^ ,.\\007]+)', 'g');\r
+ re = new RegExp('(?:^|\\s)([' + _kiwi.gateway.get('channel_prefix') + '][^ ,.\\007]+)', 'g');\r
msg.msg = msg.msg.replace(re, function (match) {\r
- return '<a class="chan">' + match + '</a>';\r
+ return '<a class="chan" data-channel="' + match.trim() + '">' + match + '</a>';\r
});\r
\r
\r
- // Make links clickable\r
- msg.msg = msg.msg.replace(/((https?\:\/\/|ftp\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]*))?/gi, function (url) {\r
- var nice;\r
+ // Parse any links found\r
+ msg.msg = msg.msg.replace(/(([A-Za-z0-9\-]+\:\/\/)|(www\.))([\w.\-]+)([a-zA-Z]{2,6})(:[0-9]+)?(\/[\w#!:.?$'()[\]*,;~+=&%@!\-\/]*)?/gi, function (url) {\r
+ var nice = url,\r
+ extra_html = '';\r
\r
- // Add the http is no protoocol was found\r
+ // Add the http if no protoocol was found\r
if (url.match(/^www\./)) {\r
url = 'http://' + url;\r
}\r
\r
- nice = url;\r
+ // Shorten the displayed URL if it's going to be too long\r
if (nice.length > 100) {\r
nice = nice.substr(0, 100) + '...';\r
}\r
\r
- return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url + '">' + nice + '</a>';\r
+ // Get any media HTML if supported\r
+ extra_html = _kiwi.view.MediaMessage.buildHtml(url);\r
+\r
+ // Make the link clickable\r
+ return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url + '">' + nice + '</a> ' + extra_html;\r
});\r
\r
\r
// Activity/alerts based on the type of new message\r
if (msg.type.match(/^action /)) {\r
this.alert('action');\r
+\r
} else if (is_highlight) {\r
_kiwi.app.view.alertWindow('* People are talking!');\r
this.alert('highlight');\r
+\r
} else {\r
// If this is the active panel, send an alert out\r
if (this.model.isActive()) {\r
this.alert('activity');\r
}\r
\r
+ // Update the activity counters\r
+ (function () {\r
+ // Only inrement the counters if we're not the active panel\r
+ if (this.model.isActive()) return;\r
+\r
+ var $act = this.model.tab.find('.activity');\r
+ $act.text((parseInt($act.text(), 10) || 0) + 1);\r
+ if ($act.text() === '0') {\r
+ $act.addClass('zero');\r
+ } else {\r
+ $act.removeClass('zero');\r
+ }\r
+ }).apply(this);\r
+\r
this.scrollToBottom();\r
\r
// Make sure our DOM isn't getting too large (Acts as scrollback)\r
},\r
chanClick: function (event) {\r
if (event.target) {\r
- _kiwi.gateway.join($(event.target).text());\r
+ _kiwi.gateway.join($(event.target).data('channel'));\r
} else {\r
// IE...\r
- _kiwi.gateway.join($(event.srcElement).text());\r
+ _kiwi.gateway.join($(event.srcElement).data('channel'));\r
+ }\r
+ },\r
+\r
+ mediaClick: function (event) {\r
+ var $media = $(event.target).parents('.media');\r
+ var media_message;\r
+\r
+ if ($media.data('media')) {\r
+ media_message = $media.data('media');\r
+ } else {\r
+ media_message = new _kiwi.view.MediaMessage({el: $media[0]});\r
+ $media.data('media', media_message);\r
}\r
+\r
+ $media.data('media', media_message);\r
+\r
+ media_message.open();\r
},\r
\r
+ // Cursor hovers over a message\r
msgEnter: function (event) {\r
var nick_class;\r
\r
$('.'+nick_class).addClass('global_nick_highlight');\r
},\r
\r
+ // Cursor leaves message\r
msgLeave: function (event) {\r
var nick_class;\r
\r
// Show this panels memberlist\r
var members = this.model.get("members");\r
if (members) {\r
- $('#memberlists').show();\r
+ $('#memberlists').removeClass('disabled');\r
members.view.show();\r
} else {\r
// Memberlist not found for this panel, hide any active ones\r
- $('#memberlists').hide().children().removeClass('active');\r
+ $('#memberlists').addClass('disabled').children().removeClass('active');\r
}\r
\r
_kiwi.app.view.doLayout();\r
+\r
+ // Remove any alerts and activity counters for this panel\r
this.alert('none');\r
+ this.model.tab.find('.activity').text('0').addClass('zero');\r
\r
this.trigger('active', this.model);\r
- _kiwi.app.panels.trigger('active', this.model);\r
+ _kiwi.app.panels.trigger('active', this.model, _kiwi.app.panels.active);\r
\r
this.scrollToBottom(true);\r
},\r
initialize: function (options) {\r
this.initializePanel(options);\r
this.model.bind('change:topic', this.topic, this);\r
+\r
+ // Only show the loader if this is a channel (ie. not a query)\r
+ if (this.model.isChannel()) {\r
+ this.$el.append('<div class="initial_loader" style="margin:1em;text-align:center;">Joining channel.. <span class="loader"></span></div>');\r
+ }\r
+ },\r
+\r
+ // Override the existing newMsg() method to remove the joining channel loader\r
+ newMsg: function () {\r
+ this.$el.find('.initial_loader').slideUp(function () {\r
+ $(this).remove();\r
+ });\r
+\r
+ return this.constructor.__super__.newMsg.apply(this, arguments);\r
},\r
\r
topic: function (topic) {\r
\r
panelAdded: function (panel) {\r
// Add a tab to the panel\r
- panel.tab = $('<li><span>' + (panel.get('title') || panel.get('name')) + '</span></li>');\r
+ panel.tab = $('<li><span>' + (panel.get('title') || panel.get('name')) + '</span><div class="activity"></div></li>');\r
\r
if (panel.isServer()) {\r
panel.tab.addClass('server');\r
_kiwi.app.view.doLayout();\r
},\r
\r
- panelActive: function (panel) {\r
+ panelActive: function (panel, previously_active_panel) {\r
// Remove any existing tabs or part images\r
$('.part', this.$el).remove();\r
this.tabs_applets.children().removeClass('active');\r
meta;\r
\r
if (navigator.appVersion.indexOf("Mac") !== -1) {\r
- meta = ev.ctrlKey;\r
+ meta = ev.metaKey;\r
} else {\r
meta = ev.altKey;\r
}\r
}\r
break;\r
\r
- case (ev.keyCode === 37 && meta): // left\r
+ case (ev.keyCode === 219 && meta): // [ + meta\r
_kiwi.app.panels.view.prev();\r
return false;\r
\r
- case (ev.keyCode === 39 && meta): // right\r
+ case (ev.keyCode === 221 && meta): // ] + meta\r
_kiwi.app.panels.view.next();\r
return false;\r
\r
}\r
\r
(function () {\r
- var tokens = inp_val.substring(0, inp[0].selectionStart).split(' '),\r
- val,\r
- p1,\r
- newnick,\r
- range,\r
- nick = tokens[tokens.length - 1];\r
+ var tokens, // Words before the cursor position\r
+ val, // New value being built up\r
+ p1, // Position in the value just before the nick \r
+ newnick, // New nick to be displayed (cycles through)\r
+ range, // TextRange for setting new text cursor position\r
+ nick, // Current nick in the value\r
+ trailing = ': '; // Text to be inserted after a tabbed nick\r
+\r
+ tokens = inp_val.substring(0, inp[0].selectionStart).split(' ');\r
+ if (tokens[tokens.length-1] == ':')\r
+ tokens.pop();\r
+\r
+ nick = tokens[tokens.length - 1];\r
+\r
if (this.tabcomplete.prefix === '') {\r
this.tabcomplete.prefix = nick;\r
}\r
});\r
\r
if (this.tabcomplete.data.length > 0) {\r
+ // Get the current value before cursor position\r
p1 = inp[0].selectionStart - (nick.length);\r
val = inp_val.substr(0, p1);\r
+\r
+ // Include the current selected nick\r
newnick = this.tabcomplete.data.shift();\r
this.tabcomplete.data.push(newnick);\r
val += newnick;\r
+\r
+ if (inp_val.substr(inp[0].selectionStart, 2) !== trailing)\r
+ val += trailing;\r
+\r
+ // Now include the rest of the current value\r
val += inp_val.substr(inp[0].selectionStart);\r
+\r
inp.val(val);\r
\r
+ // Move the cursor position to the end of the nick\r
if (inp[0].setSelectionRange) {\r
- inp[0].setSelectionRange(p1 + newnick.length, p1 + newnick.length);\r
+ inp[0].setSelectionRange(p1 + newnick.length + trailing.length, p1 + newnick.length + trailing.length);\r
} else if (inp[0].createTextRange) { // not sure if this bit is actually needed....\r
range = inp[0].createTextRange();\r
range.collapse(true);\r
- range.moveEnd('character', p1 + newnick.length);\r
- range.moveStart('character', p1 + newnick.length);\r
+ range.moveEnd('character', p1 + newnick.length + trailing.length);\r
+ range.moveStart('character', p1 + newnick.length + trailing.length);\r
range.select();\r
}\r
}\r
\r
// Trigger the command events\r
this.trigger('command', {command: command, params: params});\r
- this.trigger('command_' + command, {command: command, params: params});\r
+ this.trigger('command:' + command, {command: command, params: params});\r
\r
// If we didn't have any listeners for this event, fire a special case\r
// TODO: This feels dirty. Should this really be done..?\r
- if (!this._callbacks['command_' + command]) {\r
+ if (!this._callbacks['command:' + command]) {\r
this.trigger('unknown_command', {command: command, params: params});\r
}\r
}\r
opt.timeout = opt.timeout || 5000;\r
\r
this.$el.text(text).attr('class', opt.type);\r
- this.$el.slideDown(_kiwi.app.view.doLayout);\r
+ this.$el.slideDown($.proxy(_kiwi.app.view.doLayout, this));\r
\r
if (opt.timeout) this.doTimeout(opt.timeout);\r
},\r
},\r
\r
hide: function () {\r
- this.$el.slideUp(_kiwi.app.view.doLayout);\r
+ this.$el.slideUp($.proxy(_kiwi.app.view.doLayout, this));\r
},\r
\r
doTimeout: function (length) {\r
\r
_kiwi.view.Application = Backbone.View.extend({\r
initialize: function () {\r
- $(window).resize(this.doLayout);\r
- $('#toolbar').resize(this.doLayout);\r
- $('#controlbox').resize(this.doLayout);\r
+ var that = this;\r
+\r
+ $(window).resize(function() { that.doLayout.apply(that); });\r
+ $('#toolbar').resize(function() { that.doLayout.apply(that); });\r
+ $('#controlbox').resize(function() { that.doLayout.apply(that); });\r
\r
// Change the theme when the config is changed\r
_kiwi.global.settings.on('change:theme', this.updateTheme, this);\r
this.updateTheme(getQueryVariable('theme'));\r
\r
+ _kiwi.global.settings.on('change:channel_list_style', this.setTabLayout, this);\r
+ this.setTabLayout(_kiwi.global.settings.get('channel_list_style'));\r
+\r
+ _kiwi.global.settings.on('change:show_timestamps', this.displayTimestamps, this);\r
+ this.displayTimestamps(_kiwi.global.settings.get('show_timestamps'));\r
+\r
this.doLayout();\r
\r
$(document).keydown(this.setKeyFocus);\r
},\r
\r
\r
+ setTabLayout: function (layout_style) {\r
+ // If called by the settings callback, get the correct new_value\r
+ if (layout_style === _kiwi.global.settings) {\r
+ layout_style = arguments[1];\r
+ }\r
+ \r
+ if (layout_style == 'list') {\r
+ this.$el.addClass('chanlist_treeview');\r
+ } else {\r
+ this.$el.removeClass('chanlist_treeview');\r
+ }\r
+ \r
+ this.doLayout();\r
+ },\r
+\r
+\r
+ displayTimestamps: function (show_timestamps) {\r
+ // If called by the settings callback, get the correct new_value\r
+ if (show_timestamps === _kiwi.global.settings) {\r
+ show_timestamps = arguments[1];\r
+ }\r
+\r
+ if (show_timestamps) {\r
+ this.$el.addClass('timestamps');\r
+ } else {\r
+ this.$el.removeClass('timestamps');\r
+ }\r
+ },\r
+\r
+\r
// Globally shift focus to the command input box on a keypress\r
setKeyFocus: function (ev) {\r
// If we're copying text, don't shift focus\r
}\r
\r
// If we're typing into an input box somewhere, ignore\r
- if ((ev.target.tagName.toLowerCase() === 'input') || $(ev.target).attr('contenteditable')) {\r
+ if ((ev.target.tagName.toLowerCase() === 'input') || (ev.target.tagName.toLowerCase() === 'textarea') || $(ev.target).attr('contenteditable')) {\r
return;\r
}\r
\r
\r
\r
doLayout: function () {\r
- var el_panels = $('#panels');\r
- var el_memberlists = $('#memberlists');\r
- var el_toolbar = $('#toolbar');\r
- var el_controlbox = $('#controlbox');\r
- var el_resize_handle = $('#memberlists_resize_handle');\r
+ var el_kiwi = this.$el;\r
+ var el_panels = $('#kiwi #panels');\r
+ var el_memberlists = $('#kiwi #memberlists');\r
+ var el_toolbar = $('#kiwi #toolbar');\r
+ var el_controlbox = $('#kiwi #controlbox');\r
+ var el_resize_handle = $('#kiwi #memberlists_resize_handle');\r
\r
var css_heights = {\r
top: el_toolbar.outerHeight(true),\r
el_memberlists.css(css_heights);\r
el_resize_handle.css(css_heights);\r
\r
+ // If we have channel tabs on the side, adjust the height\r
+ if (el_kiwi.hasClass('chanlist_treeview')) {\r
+ $('#tabs', el_kiwi).css(css_heights);\r
+ }\r
+\r
+ // Determine if we have a narrow window (mobile/tablet/or even small desktop window)\r
+ if (el_kiwi.outerWidth() < 400) {\r
+ el_kiwi.addClass('narrow');\r
+ } else {\r
+ el_kiwi.removeClass('narrow');\r
+ }\r
+\r
// Set the panels width depending on the memberlist visibility\r
if (el_memberlists.css('display') != 'none') {\r
- // Handle + panels to the side of the memberlist\r
- el_panels.css('right', el_memberlists.outerWidth(true) + el_resize_handle.outerWidth(true));\r
- el_resize_handle.css('left', el_memberlists.position().left - el_resize_handle.outerWidth(true));\r
+ // Panels to the side of the memberlist\r
+ el_panels.css('right', el_memberlists.outerWidth(true));\r
+ // The resize handle sits overlapping the panels and memberlist\r
+ el_resize_handle.css('left', el_memberlists.position().left - (el_resize_handle.outerWidth(true) / 2));\r
} else {\r
- // Memberlist is hidden so handle + panels to the right edge\r
- el_panels.css('right', el_resize_handle.outerWidth(true));\r
+ // Memberlist is hidden so panels to the right edge\r
+ el_panels.css('right', 0);\r
+ // And move the handle just out of sight to the right\r
el_resize_handle.css('left', el_panels.outerWidth(true));\r
}\r
+\r
+ var input_wrap_width = parseInt($('#kiwi #controlbox .input_tools').outerWidth());\r
+ el_controlbox.find('.input_wrap').css('right', input_wrap_width + 7);\r
},\r
\r
\r
var that = this;\r
\r
if (!instant) {\r
- $('#toolbar').slideUp({queue: false, duration: 400, step: this.doLayout});\r
- $('#controlbox').slideUp({queue: false, duration: 400, step: this.doLayout});\r
+ $('#toolbar').slideUp({queue: false, duration: 400, step: $.proxy(this.doLayout, this)});\r
+ $('#controlbox').slideUp({queue: false, duration: 400, step: $.proxy(this.doLayout, this)});\r
} else {\r
$('#toolbar').slideUp(0);\r
$('#controlbox').slideUp(0);\r
var that = this;\r
\r
if (!instant) {\r
- $('#toolbar').slideDown({queue: false, duration: 400, step: this.doLayout});\r
- $('#controlbox').slideDown({queue: false, duration: 400, step: this.doLayout});\r
+ $('#toolbar').slideDown({queue: false, duration: 400, step: $.proxy(this.doLayout, this)});\r
+ $('#controlbox').slideDown({queue: false, duration: 400, step: $.proxy(this.doLayout, this)});\r
} else {\r
$('#toolbar').slideDown(0);\r
$('#controlbox').slideDown(0);\r
this.doLayout();\r
}\r
}\r
+});\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+_kiwi.view.MediaMessage = Backbone.View.extend({\r
+ events: {\r
+ 'click .media_close': 'close'\r
+ },\r
+\r
+ initialize: function () {\r
+ // Get the URL from the data\r
+ this.url = this.$el.data('url');\r
+ },\r
+\r
+ // Close the media content and remove it from display\r
+ close: function () {\r
+ var that = this;\r
+ this.$content.slideUp('fast', function () {\r
+ that.$content.remove();\r
+ });\r
+ },\r
+\r
+ // Open the media content within its wrapper\r
+ open: function () {\r
+ // Create the content div if we haven't already\r
+ if (!this.$content) {\r
+ this.$content = $('<div class="media_content"><a class="media_close"><i class="icon-chevron-up"></i> Close media</a><br /><div class="content"></div></div>');\r
+ this.$content.find('.content').append(this.mediaTypes[this.$el.data('type')].apply(this, []) || 'Not found :(');\r
+ }\r
+\r
+ // Now show the content if not already\r
+ if (!this.$content.is(':visible')) {\r
+ // Hide it first so the slideDown always plays\r
+ this.$content.hide();\r
+\r
+ // Add the media content and slide it into view\r
+ this.$el.append(this.$content);\r
+ this.$content.slideDown();\r
+ }\r
+ },\r
+\r
+\r
+\r
+ // Generate the media content for each recognised type\r
+ mediaTypes: {\r
+ twitter: function () {\r
+ var tweet_id = this.$el.data('tweetid');\r
+ var that = this;\r
+\r
+ $.getJSON('https://api.twitter.com/1/statuses/oembed.json?id=' + tweet_id + '&callback=?', function (data) {\r
+ that.$content.find('.content').html(data.html);\r
+ });\r
+\r
+ return $('<div>Loading tweet..</div>');\r
+ },\r
+\r
+\r
+ image: function () {\r
+ return $('<a href="' + this.url + '" target="_blank"><img height="100" src="' + this.url + '" /></a>');\r
+ },\r
+\r
+\r
+ reddit: function () {\r
+ var that = this;\r
+ var matches = (/reddit\.com\/r\/([a-zA-Z0-9_\-]+)\/comments\/([a-z0-9]+)\/([^\/]+)?/gi).exec(this.url);\r
+\r
+ $.getJSON('http://www.' + matches[0] + '.json?jsonp=?', function (data) {\r
+ console.log('Loaded reddit data', data);\r
+ var post = data[0].data.children[0].data;\r
+ var thumb = '';\r
+\r
+ // Show a thumbnail if there is one\r
+ if (post.thumbnail) {\r
+ //post.thumbnail = 'http://www.eurotunnel.com/uploadedImages/commercial/back-steps-icon-arrow.png';\r
+\r
+ // Hide the thumbnail if an over_18 image\r
+ if (post.over_18) {\r
+ thumb = '<span class="thumbnail_nsfw" onclick="$(this).find(\'p\').remove(); $(this).find(\'img\').css(\'visibility\', \'visible\');">';\r
+ thumb += '<p style="font-size:0.9em;line-height:1.2em;cursor:pointer;">Show<br />NSFW</p>';\r
+ thumb += '<img src="' + post.thumbnail + '" class="thumbnail" style="visibility:hidden;" />';\r
+ thumb += '</span>';\r
+ } else {\r
+ thumb = '<img src="' + post.thumbnail + '" class="thumbnail" />';\r
+ }\r
+ }\r
+\r
+ // Build the template string up\r
+ var tmpl = '<div>' + thumb + '<b><%- title %></b><br />Posted by <%- author %>. ';\r
+ tmpl += '<i class="icon-arrow-up"></i> <%- ups %> <i class="icon-arrow-down"></i> <%- downs %><br />';\r
+ tmpl += '<%- num_comments %> comments made. <a href="http://www.reddit.com<%- permalink %>">View post</a></div>';\r
+\r
+ that.$content.find('.content').html(_.template(tmpl, post));\r
+ });\r
+\r
+ return $('<div>Loading Reddit thread..</div>');\r
+ }\r
+ }\r
+\r
+}, {\r
+\r
+ // Build the closed media HTML from a URL\r
+ buildHtml: function (url) {\r
+ var html = '', matches;\r
+\r
+ // Is it an image?\r
+ if (url.match(/(\.jpe?g|\.gif|\.bmp|\.png)\??$/i)) {\r
+ html += '<span class="media image" data-type="image" data-url="' + url + '" title="Open Image"><a class="open"><i class="icon-chevron-right"></i></a></span>';\r
+ }\r
+\r
+ // Is it a tweet?\r
+ matches = (/https?:\/\/twitter.com\/([a-zA-Z0-9_]+)\/status\/([0-9]+)/ig).exec(url);\r
+ if (matches) {\r
+ html += '<span class="media twitter" data-type="twitter" data-url="' + url + '" data-tweetid="' + matches[2] + '" title="Show tweet information"><a class="open"><i class="icon-chevron-right"></i></a></span>';\r
+ }\r
+\r
+ // Is reddit?\r
+ matches = (/reddit\.com\/r\/([a-zA-Z0-9_\-]+)\/comments\/([a-z0-9]+)\/([^\/]+)?/gi).exec(url);\r
+ if (matches) {\r
+ html += '<span class="media reddit" data-type="reddit" data-url="' + url + '" title="Reddit thread"><a class="open"><i class="icon-chevron-right"></i></a></span>';\r
+ }\r
+\r
+ return html;\r
+ }\r
});
\ No newline at end of file