2014-03-17 04:35:58 -04:00
#= require modernizr
#= require jquery
#= require date
2014-03-25 21:30:00 -04:00
#= require favcount
2014-03-17 04:35:58 -04:00
#= require flexie
#= require keymaster
2012-03-21 23:40:22 -04:00
# Add a new jQuery selector expression which does a case-insensitive :contains
2014-03-25 21:08:52 -04:00
jQuery . expr [ " : " ] . icontains = (a, i, m) ->
2012-03-21 23:40:22 -04:00
( a . textContent ? a . innerText ? " " ) . toUpperCase ( ) . indexOf ( m [ 3 ] . toUpperCase ( ) ) >= 0
2011-05-29 02:46:38 -04:00
class MailCatcher
constructor: ->
2014-03-25 21:08:52 -04:00
$ ( " # messages tr " ) . live " click " , (e) =>
2011-07-07 03:57:28 -04:00
e . preventDefault ( )
2014-03-25 21:08:52 -04:00
@ loadMessage $ ( e . currentTarget ) . attr ( " data-message-id " )
2011-05-29 02:46:38 -04:00
2014-03-25 21:08:52 -04:00
$ ( " input[name=search] " ) . keyup (e) =>
2012-03-21 23:40:22 -04:00
query = $ . trim $ ( e . currentTarget ) . val ( )
if query
@ searchMessages query
2012-03-12 06:29:42 -04:00
else
2012-03-21 23:40:22 -04:00
@ clearSearch ( )
2012-03-12 06:29:42 -04:00
2014-03-25 21:08:52 -04:00
$ ( " # message .views .format.tab a " ) . live " click " , (e) =>
2011-07-07 03:57:28 -04:00
e . preventDefault ( )
2014-03-25 21:08:52 -04:00
@ loadMessageBody @ selectedMessage ( ) , $ ( $ ( e . currentTarget ) . parent ( " li " ) ) . data ( " message-format " )
2011-06-10 08:47:38 -04:00
2014-03-25 21:08:52 -04:00
$ ( " # message iframe " ) . load =>
2013-07-28 16:57:36 -04:00
@ decorateMessageBody ( )
2011-07-07 04:08:32 -04:00
2014-03-25 21:08:52 -04:00
$ ( " # resizer " ) . live
2013-08-21 18:49:34 -04:00
mousedown: (e) =>
2011-07-06 23:39:05 -04:00
e . preventDefault ( )
$ ( window ) . bind events =
2013-08-21 18:49:34 -04:00
mouseup: (e) =>
2011-07-06 23:39:05 -04:00
e . preventDefault ( )
$ ( window ) . unbind events
2013-08-21 18:49:34 -04:00
mousemove: (e) =>
2011-07-06 23:39:05 -04:00
e . preventDefault ( )
2013-08-21 18:49:34 -04:00
@ resizeTo e . clientY
@ resizeToSaved ( )
2011-07-06 23:39:05 -04:00
2014-03-25 21:08:52 -04:00
$ ( " nav.app .clear a " ) . live " click " , (e) =>
2011-10-07 11:31:02 -04:00
e . preventDefault ( )
2011-05-31 13:15:05 -04:00
if confirm " You will lose all your received messages. \n \n Are you sure you want to clear all messages? "
2011-06-10 08:47:38 -04:00
$ . ajax
2014-03-25 21:08:52 -04:00
url: " /messages "
type: " DELETE "
2013-04-08 16:20:30 -04:00
success: =>
2012-10-29 19:00:50 -04:00
@ unselectMessage ( )
2014-03-25 21:29:36 -04:00
@ updateMessagesCount ( )
2011-05-31 13:15:05 -04:00
error: ->
2014-03-25 21:08:52 -04:00
alert " Error while clearing all messages. "
2011-05-29 02:46:38 -04:00
2014-03-25 21:08:52 -04:00
$ ( " nav.app .quit a " ) . live " click " , (e) =>
2011-10-07 11:31:02 -04:00
e . preventDefault ( )
2011-05-31 13:14:56 -04:00
if confirm " You will lose all your received messages. \n \n Are you sure you want to quit? "
$ . ajax
2014-03-25 21:08:52 -04:00
type: " DELETE "
2011-05-31 13:14:56 -04:00
success: ->
2014-03-25 21:08:52 -04:00
location . replace $ ( " body > header h1 a " ) . attr ( " href " )
2011-05-31 13:14:56 -04:00
error: ->
2014-03-25 21:08:52 -04:00
alert " Error while quitting. "
2011-06-10 08:47:38 -04:00
2014-03-25 21:30:00 -04:00
@favcount = new Favcount ( $ ( """ link[rel= " icon " ] """ ) . attr ( " href " ) )
2014-03-25 21:08:52 -04:00
key " up " , =>
2012-10-24 17:54:07 -04:00
if @ selectedMessage ( )
2014-03-25 21:08:52 -04:00
@ loadMessage $ ( " # messages tr.selected " ) . prev ( ) . data ( " message-id " )
2012-10-24 17:54:07 -04:00
else
2014-03-25 21:08:52 -04:00
@ loadMessage $ ( " # messages tbody tr[data-message-id]:first " ) . data ( " message-id " )
2012-10-24 17:21:08 -04:00
false
2012-04-19 11:26:40 -04:00
2014-03-25 21:08:52 -04:00
key " down " , =>
2012-10-24 17:54:07 -04:00
if @ selectedMessage ( )
2014-03-25 21:08:52 -04:00
@ loadMessage $ ( " # messages tr.selected " ) . next ( ) . data ( " message-id " )
2012-10-24 17:54:07 -04:00
else
2014-03-25 21:08:52 -04:00
@ loadMessage $ ( " # messages tbody tr[data-message-id]:first " ) . data ( " message-id " )
2012-10-24 17:21:08 -04:00
false
2012-04-19 11:26:40 -04:00
2014-03-25 21:08:52 -04:00
key " ⌘+up, ctrl+up " , =>
@ loadMessage $ ( " # messages tbody tr[data-message-id]:first " ) . data ( " message-id " )
2012-10-24 17:21:08 -04:00
false
2012-04-19 11:26:40 -04:00
2014-03-25 21:08:52 -04:00
key " ⌘+down, ctrl+down " , =>
@ loadMessage $ ( " # messages tbody tr[data-message-id]:last " ) . data ( " message-id " )
2012-10-24 17:21:08 -04:00
false
2012-04-19 11:26:40 -04:00
2014-03-25 21:08:52 -04:00
key " left " , =>
2012-04-19 11:26:40 -04:00
@ openTab @ previousTab ( )
2012-10-24 17:21:08 -04:00
false
2012-04-19 11:26:40 -04:00
2014-03-25 21:08:52 -04:00
key " right " , =>
2012-04-19 11:26:40 -04:00
@ openTab @ nextTab ( )
2012-10-24 17:21:08 -04:00
false
2012-04-19 11:26:40 -04:00
2014-03-25 21:08:52 -04:00
key " backspace, delete " , =>
2012-10-24 18:45:26 -04:00
id = @ selectedMessage ( )
if id ?
$ . ajax
2014-03-25 21:08:52 -04:00
url: " /messages/ " + id
type: " DELETE "
2012-10-24 19:20:33 -04:00
success: =>
2014-03-25 21:08:52 -04:00
messageRow = $ ( """ # messages tbody tr[data-message-id= " #{ id } " ] """ )
switchTo = messageRow . next ( ) . data ( " message-id " ) || messageRow . prev ( ) . data ( " message-id " )
2012-10-24 19:20:33 -04:00
messageRow . remove ( )
if switchTo
@ loadMessage switchTo
else
2012-10-29 19:00:50 -04:00
@ unselectMessage ( )
2014-03-25 21:29:36 -04:00
@ updateMessagesCount ( )
2012-10-24 19:20:33 -04:00
2012-10-24 18:45:26 -04:00
error: ->
2014-03-25 21:08:52 -04:00
alert " Error while removing message. "
2012-10-24 18:45:26 -04:00
false
2011-05-29 02:46:38 -04:00
@ refresh ( )
@ subscribe ( )
2011-06-10 08:47:38 -04:00
2011-05-29 03:42:07 -04:00
# Only here because Safari's Date parsing *sucks*
# We throw away the timezone, but you could use it for something...
parseDateRegexp: /^(\d{4})[-\/\\](\d{2})[-\/\\](\d{2})(?:\s+|T)(\d{2})[:-](\d{2})[:-](\d{2})(?:([ +-]\d{2}:\d{2}|\s*\S+|Z?))?$/
parseDate: (date) ->
if match = @ parseDateRegexp . exec ( date )
2011-07-07 01:40:22 -04:00
new Date match [ 1 ] , match [ 2 ] - 1 , match [ 3 ] , match [ 4 ] , match [ 5 ] , match [ 6 ] , 0
2011-06-10 08:47:38 -04:00
2011-12-30 03:29:52 -05:00
offsetTimeZone: (date) ->
2012-01-01 22:01:26 -05:00
offset = Date . now ( ) . getTimezoneOffset ( ) * 60000 #convert timezone difference to milliseconds
2011-12-30 03:29:52 -05:00
date . setTime ( date . getTime ( ) - offset )
date
2011-05-29 03:42:07 -04:00
formatDate: (date) ->
2012-01-01 22:01:26 -05:00
date && = @ parseDate ( date ) if typeof ( date ) == " string "
date && = @ offsetTimeZone ( date )
2011-05-29 03:42:07 -04:00
date && = date . toString ( " dddd, d MMM yyyy h:mm:ss tt " )
2011-05-29 02:46:38 -04:00
2012-04-19 11:26:40 -04:00
messagesCount: ->
2014-03-25 21:08:52 -04:00
$ ( " # messages tr " ) . length - 1
2012-04-19 11:26:40 -04:00
2014-03-25 21:29:36 -04:00
updateMessagesCount: ->
2014-03-25 21:30:00 -04:00
@ favcount . set ( @ messagesCount ( ) )
2014-03-25 21:29:36 -04:00
2012-04-19 11:26:40 -04:00
tabs: ->
2014-03-25 21:08:52 -04:00
$ ( " # message ul " ) . children ( " .tab " )
2012-04-19 11:26:40 -04:00
getTab: (i) =>
$ ( @ tabs ( ) [ i ] )
selectedTab: =>
2014-03-25 21:08:52 -04:00
@ tabs ( ) . index ( $ ( " # message li.tab.selected " ) )
2012-04-19 11:26:40 -04:00
openTab: (i) =>
2014-03-25 21:08:52 -04:00
@ getTab ( i ) . children ( " a " ) . click ( )
2012-04-19 11:26:40 -04:00
previousTab: (tab)=>
i = if tab || tab is 0 then tab else @ selectedTab ( ) - 1
i = @ tabs ( ) . length - 1 if i < 0
if @ getTab ( i ) . is ( " :visible " )
i
else
2014-03-25 21:08:52 -04:00
@ previousTab ( i - 1 )
2012-04-19 11:26:40 -04:00
nextTab: (tab) =>
i = if tab then tab else @ selectedTab ( ) + 1
i = 0 if i > @ tabs ( ) . length - 1
if @ getTab ( i ) . is ( " :visible " )
i
else
2014-03-25 21:08:52 -04:00
@ nextTab ( i + 1 )
2012-04-19 11:26:40 -04:00
2011-05-29 02:46:38 -04:00
haveMessage: (message) ->
message = message . id if message . id ?
2014-03-25 21:08:52 -04:00
$ ( """ # messages tbody tr[data-message-id= " #{ message } " ] """ ) . length > 0
2011-06-10 08:47:38 -04:00
2011-07-07 03:57:28 -04:00
selectedMessage: ->
2014-03-25 21:08:52 -04:00
$ ( " # messages tr.selected " ) . data " message-id "
2011-07-07 03:57:28 -04:00
2012-03-21 23:40:22 -04:00
searchMessages: (query) ->
2014-03-25 21:08:52 -04:00
selector = ( " :icontains( ' #{ token } ' ) " for token in query . split / \ s + / ) . join ( " " )
2012-03-21 23:40:22 -04:00
$rows = $ ( " # messages tbody tr " )
$rows . not ( selector ) . hide ( )
$rows . filter ( selector ) . show ( )
2012-03-12 06:29:42 -04:00
clearSearch: ->
2014-03-25 21:08:52 -04:00
$ ( " # messages tbody tr " ) . show ( )
2012-03-12 06:29:42 -04:00
2011-05-29 02:46:38 -04:00
addMessage: (message) ->
2014-03-25 21:08:52 -04:00
$ ( " <tr /> " ) . attr ( " data-message-id " , message . id . toString ( ) )
. append ( $ ( " <td/> " ) . text ( message . sender or " No sender " ) . toggleClass ( " blank " , ! message . sender ) )
. append ( $ ( " <td/> " ) . text ( ( message . recipients || [ ] ) . join ( " , " ) or " No receipients " ) . toggleClass ( " blank " , ! message . recipients . length ) )
. append ( $ ( " <td/> " ) . text ( message . subject or " No subject " ) . toggleClass ( " blank " , ! message . subject ) )
. append ( $ ( " <td/> " ) . text ( @ formatDate ( message . created_at ) ) )
. prependTo ( $ ( " # messages tbody " ) )
2014-03-25 21:29:36 -04:00
@ updateMessagesCount ( )
2011-06-10 08:47:38 -04:00
2012-10-24 17:25:41 -04:00
scrollToRow: (row) ->
2014-03-25 21:08:52 -04:00
relativePosition = row . offset ( ) . top - $ ( " # messages " ) . offset ( ) . top
2012-10-24 17:25:41 -04:00
if relativePosition < 0
2014-03-25 21:08:52 -04:00
$ ( " # messages " ) . scrollTop ( $ ( " # messages " ) . scrollTop ( ) + relativePosition - 20 )
2012-10-24 17:25:41 -04:00
else
2014-03-25 21:08:52 -04:00
overflow = relativePosition + row . height ( ) - $ ( " # messages " ) . height ( )
2012-10-24 17:25:41 -04:00
if overflow > 0
2014-03-25 21:08:52 -04:00
$ ( " # messages " ) . scrollTop ( $ ( " # messages " ) . scrollTop ( ) + overflow + 20 )
2012-10-24 17:25:41 -04:00
2012-10-29 19:00:50 -04:00
unselectMessage: ->
2014-03-25 21:08:52 -04:00
$ ( " # messages tbody, # message .metadata dd " ) . empty ( )
$ ( " # message .metadata .attachments " ) . hide ( )
$ ( " # message iframe " ) . attr ( " src " , " about:blank " )
2012-10-29 19:00:50 -04:00
null
2011-05-29 02:46:38 -04:00
loadMessage: (id) ->
id = id . id if id ? . id ?
2014-03-25 21:08:52 -04:00
id || = $ ( " # messages tr.selected " ) . attr " data-message-id "
2011-06-10 08:47:38 -04:00
2011-05-29 02:46:38 -04:00
if id ?
2014-03-25 21:08:52 -04:00
$ ( " # messages tbody tr:not([data-message-id= ' #{ id } ' ]) " ) . removeClass ( " selected " )
2012-10-29 18:34:14 -04:00
messageRow = $ ( " # messages tbody tr[data-message-id= ' #{ id } ' ] " )
2014-03-25 21:08:52 -04:00
messageRow . addClass ( " selected " )
2012-10-24 17:25:41 -04:00
@ scrollToRow ( messageRow )
2011-06-10 08:47:38 -04:00
2012-10-29 18:34:14 -04:00
$ . getJSON " /messages/ #{ id } .json " , (message) =>
2014-03-25 21:08:52 -04:00
$ ( " # message .metadata dd.created_at " ) . text ( @ formatDate message . created_at )
$ ( " # message .metadata dd.from " ) . text ( message . sender )
$ ( " # message .metadata dd.to " ) . text ( ( message . recipients || [ ] ) . join ( " , " ) )
$ ( " # message .metadata dd.subject " ) . text ( message . subject )
$ ( " # message .views .tab.format " ) . each (i, el) ->
2011-05-29 02:46:38 -04:00
$el = $ ( el )
2014-03-25 21:08:52 -04:00
format = $el . attr ( " data-message-format " )
2011-05-29 02:46:38 -04:00
if $ . inArray ( format , message . formats ) >= 0
2014-03-25 21:08:52 -04:00
$el . find ( " a " ) . attr ( " href " , " /messages/ #{ id } . #{ format } " )
2011-05-29 02:46:38 -04:00
$el . show ( )
else
$el . hide ( )
2011-06-10 08:47:38 -04:00
2011-05-31 12:40:13 -04:00
if $ ( " # message .views .tab.selected:not(:visible) " ) . length
2014-03-25 21:08:52 -04:00
$ ( " # message .views .tab.selected " ) . removeClass ( " selected " )
$ ( " # message .views .tab:visible:first " ) . addClass ( " selected " )
2011-06-10 08:47:38 -04:00
2011-05-29 02:46:38 -04:00
if message . attachments . length
2014-03-25 21:08:52 -04:00
$ul = $ ( " <ul/> " ) . appendTo ( $ ( " # message .metadata dd.attachments " ) . empty ( ) )
2011-07-08 02:47:41 -04:00
2011-05-29 02:46:38 -04:00
$ . each message . attachments , (i, attachment) ->
2014-03-25 21:08:52 -04:00
$ul . append ( $ ( " <li> " ) . append ( $ ( " <a> " ) . attr ( " href " , attachment [ " href " ] ) . addClass ( attachment [ " type " ] . split ( " / " , 1 ) [ 0 ] ) . addClass ( attachment [ " type " ] . replace ( " / " , " - " ) ) . text ( attachment [ " filename " ] ) ) )
$ ( " # message .metadata .attachments " ) . show ( )
2011-05-29 02:46:38 -04:00
else
2014-03-25 21:08:52 -04:00
$ ( " # message .metadata .attachments " ) . hide ( )
2011-06-10 08:47:38 -04:00
2014-03-25 21:08:52 -04:00
$ ( " # message .views .download a " ) . attr ( " href " , " /messages/ #{ id } .eml " )
2011-06-10 08:47:38 -04:00
2014-03-26 05:33:37 -04:00
@ loadMessageBody ( )
2011-07-07 04:08:32 -04:00
# XXX: These should probably cache their iframes for the current message now we're using a remote service:
2011-05-29 02:46:38 -04:00
loadMessageBody: (id, format) ->
2011-07-07 03:57:28 -04:00
id || = @ selectedMessage ( )
2014-03-25 21:08:52 -04:00
format || = $ ( " # message .views .tab.format.selected " ) . attr ( " data-message-format " )
format || = " html "
2011-06-10 08:47:38 -04:00
2014-03-25 21:08:52 -04:00
$ ( """ # message .views .tab[data-message-format= " #{ format } " ]:not(.selected) """ ) . addClass ( " selected " )
$ ( """ # message .views .tab:not([data-message-format= " #{ format } " ]).selected """ ) . removeClass ( " selected " )
2011-06-10 08:47:38 -04:00
2011-05-29 02:46:38 -04:00
if id ?
2014-03-25 21:08:52 -04:00
$ ( " # message iframe " ) . attr ( " src " , " /messages/ #{ id } . #{ format } " )
2013-07-14 15:17:37 -04:00
2013-07-28 16:57:36 -04:00
decorateMessageBody: ->
2014-03-25 21:08:52 -04:00
format = $ ( " # message .views .tab.format.selected " ) . attr ( " data-message-format " )
2014-03-17 01:53:13 -04:00
switch format
2014-03-25 21:08:52 -04:00
when " html "
body = $ ( " # message iframe " ) . contents ( ) . find ( " body " )
2013-07-14 15:17:37 -04:00
$ ( " a " , body ) . attr ( " target " , " _blank " )
2014-03-25 21:08:52 -04:00
when " plain "
message_iframe = $ ( " # message iframe " ) . contents ( )
2013-07-28 16:57:36 -04:00
text = message_iframe . text ( )
2014-03-25 21:08:52 -04:00
text = text . replace ( /((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?)/g , """ <a href= " $1 " target= " _blank " >$1</a> """ )
text = text . replace ( /\n/g , " <br/> " )
message_iframe . find ( " html " ) . html ( " <html><body> #{ text } </html></body> " )
2013-07-14 15:17:37 -04:00
2011-05-29 02:46:38 -04:00
refresh: ->
2014-03-25 21:08:52 -04:00
$ . getJSON " /messages " , (messages) =>
2011-05-29 02:46:38 -04:00
$ . each messages , (i, message) =>
unless @ haveMessage message
@ addMessage message
2014-03-26 05:30:59 -04:00
@ updateMessagesCount ( )
2011-05-29 02:46:38 -04:00
subscribe: ->
if WebSocket ?
@ subscribeWebSocket ( )
else
@ subscribePoll ( )
subscribeWebSocket: ->
2015-01-17 00:41:51 -05:00
secure = window . location . protocol is " https: "
protocol = if secure then " wss " else " ws "
@websocket = new WebSocket ( " #{ protocol } :// #{ window . location . host } /messages " )
2011-05-29 02:46:38 -04:00
@websocket.onmessage = (event) =>
@ addMessage $ . parseJSON event . data
subscribePoll: ->
unless @ refreshInterval ?
@refreshInterval = setInterval ( => @ refresh ( ) ) , 1000
2014-03-25 21:08:52 -04:00
resizeToSavedKey: " mailcatcherSeparatorHeight "
2013-08-21 18:49:34 -04:00
resizeTo: (height) ->
2014-03-25 21:08:52 -04:00
$ ( " # messages " ) . css
height: height - $ ( " # messages " ) . offset ( ) . top
2013-08-21 18:49:34 -04:00
window . localStorage ? . setItem ( @ resizeToSavedKey , height )
resizeToSaved: ->
height = parseInt ( window . localStorage ? . getItem ( @ resizeToSavedKey ) )
unless isNaN height
@ resizeTo height
2011-05-29 02:46:38 -04:00
2011-06-10 08:47:38 -04:00
$ -> window . MailCatcher = new MailCatcher