mailcatcher-jruby 1.1.4 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
- module MailCatcher
2
- VERSION = "1.1.4"
3
- end
1
+ module MailCatcher
2
+ VERSION = "1.1.5"
3
+ end
@@ -1,152 +1,152 @@
1
- require 'sinatra'
2
- require 'pathname'
3
- require 'net/http'
4
- require 'uri'
5
- require 'haml'
6
- #require 'skinny'
7
-
8
-
9
- class Sinatra::Request
10
- #include Skinny::Helpers
11
- end
12
-
13
- class MailCatcher::Web < Sinatra::Base
14
- use ActiveRecord::ConnectionAdapters::ConnectionManagement
15
-
16
- set :root, File.expand_path("#{__FILE__}/../../..")
17
- set :haml, :format => :html5
18
-
19
- get '/' do
20
- haml :index
21
- end
22
-
23
- delete '/' do
24
- if MailCatcher.quittable?
25
- MailCatcher.quit!
26
- status 204
27
- else
28
- status 403
29
- end
30
- end
31
-
32
- get '/messages' do
33
- # if request.websocket?
34
- # request.websocket!(
35
- # :on_start => proc do |websocket|
36
- # subscription = MailCatcher::Events::MessageAdded.subscribe { |message| websocket.send_message message.to_json }
37
- # websocket.on_close do |websocket|
38
- # MailCatcher::Events::MessageAdded.unsubscribe subscription
39
- # end
40
- # end)
41
- # else
42
- MailCatcher::Mail.messages.to_json
43
- # end
44
- end
45
-
46
- delete '/messages' do
47
- MailCatcher::Mail.delete!
48
- status 204
49
- end
50
-
51
- get '/messages/:id.json' do
52
- id = params[:id].to_i
53
- if message = MailCatcher::Mail.message(id)
54
- message.merge({
55
- "formats" => [
56
- "source",
57
- ("html" if MailCatcher::Mail.message_has_html? id),
58
- ("plain" if MailCatcher::Mail.message_has_plain? id)
59
- ].compact,
60
- "attachments" => MailCatcher::Mail.message_attachments(id).map do |attachment|
61
- attachment.merge({"href" => "/messages/#{escape(id)}/parts/#{escape(attachment['cid'])}"})
62
- end,
63
- }).to_json
64
- else
65
- not_found
66
- end
67
- end
68
-
69
- get '/messages/:id.html' do
70
- id = params[:id].to_i
71
- if part = MailCatcher::Mail.message_part_html(id)
72
- content_type part["type"], :charset => (part["charset"] || "utf8")
73
-
74
- body = part["body"]
75
-
76
- # Rewrite body to link to embedded attachments served by cid
77
- body.gsub! /cid:([^'"> ]+)/, "#{id}/parts/\\1"
78
-
79
- body
80
- else
81
- not_found
82
- end
83
- end
84
-
85
- get "/messages/:id.plain" do
86
- id = params[:id].to_i
87
- if part = MailCatcher::Mail.message_part_plain(id)
88
- content_type part["type"], :charset => (part["charset"] || "utf8")
89
- part["body"]
90
- else
91
- not_found
92
- end
93
- end
94
-
95
- get "/messages/:id.source" do
96
- id = params[:id].to_i
97
- if message = MailCatcher::Mail.message(id)
98
- content_type "text/plain"
99
- message["source"]
100
- else
101
- not_found
102
- end
103
- end
104
-
105
- get "/messages/:id.eml" do
106
- id = params[:id].to_i
107
- if message = MailCatcher::Mail.message(id)
108
- content_type "message/rfc822"
109
- message["source"]
110
- else
111
- not_found
112
- end
113
- end
114
-
115
- get "/messages/:id/parts/:cid" do
116
- id = params[:id].to_i
117
- if part = MailCatcher::Mail.message_part_cid(id, params[:cid])
118
- content_type part["type"], :charset => (part["charset"] || "utf8")
119
- attachment part["filename"] if part["is_attachment"] == 1
120
- body part["body"].to_s
121
- else
122
- not_found
123
- end
124
- end
125
-
126
- get "/messages/:id/analysis.?:format?" do
127
- id = params[:id].to_i
128
- if part = MailCatcher::Mail.message_part_html(id)
129
- # TODO: Server-side cache? Make the browser cache based on message create time? Hmm.
130
- uri = URI.parse("http://api.getfractal.com/api/v2/validate#{"/format/#{params[:format]}" if params[:format].present?}")
131
- response = Net::HTTP.post_form(uri, :api_key => "5c463877265251386f516f7428", :html => part["body"])
132
- content_type ".#{params[:format]}" if params[:format].present?
133
- body response.body
134
- else
135
- not_found
136
- end
137
- end
138
-
139
- delete '/messages/:id' do
140
- id = params[:id].to_i
141
- if message = MailCatcher::Mail.message(id)
142
- MailCatcher::Mail.delete_message!(id)
143
- status 204
144
- else
145
- not_found
146
- end
147
- end
148
-
149
- not_found do
150
- "<html><body><h1>No Dice</h1><p>The message you were looking for does not exist, or doesn't have content of this type.</p></body></html>"
151
- end
152
- end
1
+ require 'sinatra'
2
+ require 'pathname'
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'haml'
6
+ #require 'skinny'
7
+
8
+
9
+ class Sinatra::Request
10
+ #include Skinny::Helpers
11
+ end
12
+
13
+ class MailCatcher::Web < Sinatra::Base
14
+ use ActiveRecord::ConnectionAdapters::ConnectionManagement
15
+
16
+ set :root, File.expand_path("#{__FILE__}/../../..")
17
+ set :haml, :format => :html5
18
+
19
+ get '/' do
20
+ haml :index
21
+ end
22
+
23
+ delete '/' do
24
+ if MailCatcher.quittable?
25
+ MailCatcher.quit!
26
+ status 204
27
+ else
28
+ status 403
29
+ end
30
+ end
31
+
32
+ get '/messages' do
33
+ # if request.websocket?
34
+ # request.websocket!(
35
+ # :on_start => proc do |websocket|
36
+ # subscription = MailCatcher::Events::MessageAdded.subscribe { |message| websocket.send_message message.to_json }
37
+ # websocket.on_close do |websocket|
38
+ # MailCatcher::Events::MessageAdded.unsubscribe subscription
39
+ # end
40
+ # end)
41
+ # else
42
+ MailCatcher::Mail.messages.to_json
43
+ # end
44
+ end
45
+
46
+ delete '/messages' do
47
+ MailCatcher::Mail.delete!
48
+ status 204
49
+ end
50
+
51
+ get '/messages/:id.json' do
52
+ id = params[:id].to_i
53
+ if message = MailCatcher::Mail.message(id)
54
+ message.merge({
55
+ "formats" => [
56
+ "source",
57
+ ("html" if MailCatcher::Mail.message_has_html? id),
58
+ ("plain" if MailCatcher::Mail.message_has_plain? id)
59
+ ].compact,
60
+ "attachments" => MailCatcher::Mail.message_attachments(id).map do |attachment|
61
+ attachment.merge({"href" => "/messages/#{escape(id)}/parts/#{escape(attachment['cid'])}"})
62
+ end,
63
+ }).to_json
64
+ else
65
+ not_found
66
+ end
67
+ end
68
+
69
+ get '/messages/:id.html' do
70
+ id = params[:id].to_i
71
+ if part = MailCatcher::Mail.message_part_html(id)
72
+ content_type part["type"], :charset => (part["charset"] || "utf8")
73
+
74
+ body = part["body"]
75
+
76
+ # Rewrite body to link to embedded attachments served by cid
77
+ body.gsub! /cid:([^'"> ]+)/, "#{id}/parts/\\1"
78
+
79
+ body
80
+ else
81
+ not_found
82
+ end
83
+ end
84
+
85
+ get "/messages/:id.plain" do
86
+ id = params[:id].to_i
87
+ if part = MailCatcher::Mail.message_part_plain(id)
88
+ content_type part["type"], :charset => (part["charset"] || "utf8")
89
+ part["body"]
90
+ else
91
+ not_found
92
+ end
93
+ end
94
+
95
+ get "/messages/:id.source" do
96
+ id = params[:id].to_i
97
+ if message = MailCatcher::Mail.message(id)
98
+ content_type "text/plain"
99
+ message["source"]
100
+ else
101
+ not_found
102
+ end
103
+ end
104
+
105
+ get "/messages/:id.eml" do
106
+ id = params[:id].to_i
107
+ if message = MailCatcher::Mail.message(id)
108
+ content_type "message/rfc822"
109
+ message["source"]
110
+ else
111
+ not_found
112
+ end
113
+ end
114
+
115
+ get "/messages/:id/parts/:cid" do
116
+ id = params[:id].to_i
117
+ if part = MailCatcher::Mail.message_part_cid(id, params[:cid])
118
+ content_type part["type"], :charset => (part["charset"] || "utf8")
119
+ attachment part["filename"] if part["is_attachment"] == 1
120
+ body part["body"].to_s
121
+ else
122
+ not_found
123
+ end
124
+ end
125
+
126
+ get "/messages/:id/analysis.?:format?" do
127
+ id = params[:id].to_i
128
+ if part = MailCatcher::Mail.message_part_html(id)
129
+ # TODO: Server-side cache? Make the browser cache based on message create time? Hmm.
130
+ uri = URI.parse("http://api.getfractal.com/api/v2/validate#{"/format/#{params[:format]}" if params[:format].present?}")
131
+ response = Net::HTTP.post_form(uri, :api_key => "5c463877265251386f516f7428", :html => part["body"])
132
+ content_type ".#{params[:format]}" if params[:format].present?
133
+ body response.body
134
+ else
135
+ not_found
136
+ end
137
+ end
138
+
139
+ delete '/messages/:id' do
140
+ id = params[:id].to_i
141
+ if message = MailCatcher::Mail.message(id)
142
+ MailCatcher::Mail.delete_message!(id)
143
+ status 204
144
+ else
145
+ not_found
146
+ end
147
+ end
148
+
149
+ not_found do
150
+ "<html><body><h1>No Dice</h1><p>The message you were looking for does not exist, or doesn't have content of this type.</p></body></html>"
151
+ end
152
+ end
@@ -1,474 +1,441 @@
1
- (function() {
2
- var MailCatcher,
3
- __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
4
-
5
- jQuery.expr[':'].icontains = function(a, i, m) {
6
- var _ref, _ref1;
7
- return ((_ref = (_ref1 = a.textContent) != null ? _ref1 : a.innerText) != null ? _ref : "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
8
- };
9
-
10
- MailCatcher = (function() {
11
- function MailCatcher() {
12
- this.nextTab = __bind(this.nextTab, this);
13
- this.previousTab = __bind(this.previousTab, this);
14
- this.openTab = __bind(this.openTab, this);
15
- this.selectedTab = __bind(this.selectedTab, this);
16
- this.getTab = __bind(this.getTab, this);
17
- $('#messages tr').live('click', (function(_this) {
18
- return function(e) {
19
- e.preventDefault();
20
- return _this.loadMessage($(e.currentTarget).attr('data-message-id'));
21
- };
22
- })(this));
23
- $('input[name=search]').keyup((function(_this) {
24
- return function(e) {
25
- var query;
26
- query = $.trim($(e.currentTarget).val());
27
- if (query) {
28
- return _this.searchMessages(query);
29
- } else {
30
- return _this.clearSearch();
31
- }
32
- };
33
- })(this));
34
- $('#message .views .format.tab a').live('click', (function(_this) {
35
- return function(e) {
36
- e.preventDefault();
37
- return _this.loadMessageBody(_this.selectedMessage(), $($(e.currentTarget).parent('li')).data('message-format'));
38
- };
39
- })(this));
40
- $('#message .views .analysis.tab a').live('click', (function(_this) {
41
- return function(e) {
42
- e.preventDefault();
43
- return _this.loadMessageAnalysis(_this.selectedMessage());
44
- };
45
- })(this));
46
- $('#message iframe').load((function(_this) {
47
- return function() {
48
- return _this.decorateMessageBody();
49
- };
50
- })(this));
51
- $('#resizer').live({
52
- mousedown: (function(_this) {
53
- return function(e) {
54
- var events;
55
- e.preventDefault();
56
- return $(window).bind(events = {
57
- mouseup: function(e) {
58
- e.preventDefault();
59
- return $(window).unbind(events);
60
- },
61
- mousemove: function(e) {
62
- e.preventDefault();
63
- return _this.resizeTo(e.clientY);
64
- }
65
- });
66
- };
67
- })(this)
68
- });
69
- this.resizeToSaved();
70
- $('nav.app .clear a').live('click', (function(_this) {
71
- return function(e) {
72
- e.preventDefault();
73
- if (confirm("You will lose all your received messages.\n\nAre you sure you want to clear all messages?")) {
74
- return $.ajax({
75
- url: '/messages',
76
- type: 'DELETE',
77
- success: function() {
78
- return _this.unselectMessage();
79
- },
80
- error: function() {
81
- return alert('Error while clearing all messages.');
82
- }
83
- });
84
- }
85
- };
86
- })(this));
87
- $('nav.app .quit a').live('click', (function(_this) {
88
- return function(e) {
89
- e.preventDefault();
90
- if (confirm("You will lose all your received messages.\n\nAre you sure you want to quit?")) {
91
- return $.ajax({
92
- type: 'DELETE',
93
- success: function() {
94
- return location.replace($('body > header h1 a').attr('href'));
95
- },
96
- error: function() {
97
- return alert('Error while quitting.');
98
- }
99
- });
100
- }
101
- };
102
- })(this));
103
- key('up', (function(_this) {
104
- return function() {
105
- if (_this.selectedMessage()) {
106
- _this.loadMessage($('#messages tr.selected').prev().data('message-id'));
107
- } else {
108
- _this.loadMessage($('#messages tbody tr[data-message-id]:first').data('message-id'));
109
- }
110
- return false;
111
- };
112
- })(this));
113
- key('down', (function(_this) {
114
- return function() {
115
- if (_this.selectedMessage()) {
116
- _this.loadMessage($('#messages tr.selected').next().data('message-id'));
117
- } else {
118
- _this.loadMessage($('#messages tbody tr[data-message-id]:first').data('message-id'));
119
- }
120
- return false;
121
- };
122
- })(this));
123
- key('⌘+up, ctrl+up', (function(_this) {
124
- return function() {
125
- _this.loadMessage($('#messages tbody tr[data-message-id]:first').data('message-id'));
126
- return false;
127
- };
128
- })(this));
129
- key('⌘+down, ctrl+down', (function(_this) {
130
- return function() {
131
- _this.loadMessage($('#messages tbody tr[data-message-id]:last').data('message-id'));
132
- return false;
133
- };
134
- })(this));
135
- key('left', (function(_this) {
136
- return function() {
137
- _this.openTab(_this.previousTab());
138
- return false;
139
- };
140
- })(this));
141
- key('right', (function(_this) {
142
- return function() {
143
- _this.openTab(_this.nextTab());
144
- return false;
145
- };
146
- })(this));
147
- key('backspace, delete', (function(_this) {
148
- return function() {
149
- var id;
150
- id = _this.selectedMessage();
151
- if (id != null) {
152
- $.ajax({
153
- url: '/messages/' + id,
154
- type: 'DELETE',
155
- success: function() {
156
- var messageRow, switchTo;
157
- messageRow = $("#messages tbody tr[data-message-id='" + id + "']");
158
- switchTo = messageRow.next().data('message-id') || messageRow.prev().data('message-id');
159
- messageRow.remove();
160
- if (switchTo) {
161
- return _this.loadMessage(switchTo);
162
- } else {
163
- return _this.unselectMessage();
164
- }
165
- },
166
- error: function() {
167
- return alert('Error while removing message.');
168
- }
169
- });
170
- }
171
- return false;
172
- };
173
- })(this));
174
- this.refresh();
175
- this.subscribe();
176
- }
177
-
178
- MailCatcher.prototype.parseDateRegexp = /^(\d{4})[-\/\\](\d{2})[-\/\\](\d{2})(?:\s+|T)(\d{2})[:-](\d{2})[:-](\d{2})(?:([ +-]\d{2}:\d{2}|\s*\S+|Z?))?$/;
179
-
180
- MailCatcher.prototype.parseDate = function(date) {
181
- var match;
182
- if (match = this.parseDateRegexp.exec(date)) {
183
- return new Date(match[1], match[2] - 1, match[3], match[4], match[5], match[6], 0);
184
- }
185
- };
186
-
187
- MailCatcher.prototype.offsetTimeZone = function(date) {
188
- var offset;
189
- offset = Date.now().getTimezoneOffset() * 60000;
190
- date.setTime(date.getTime() - offset);
191
- return date;
192
- };
193
-
194
- MailCatcher.prototype.formatDate = function(date) {
195
- if (typeof date === "string") {
196
- date && (date = this.parseDate(date));
197
- }
198
- date && (date = this.offsetTimeZone(date));
199
- return date && (date = date.toString("dddd, d MMM yyyy h:mm:ss tt"));
200
- };
201
-
202
- MailCatcher.prototype.messagesCount = function() {
203
- return $('#messages tr').length - 1;
204
- };
205
-
206
- MailCatcher.prototype.tabs = function() {
207
- return $('#message ul').children('.tab');
208
- };
209
-
210
- MailCatcher.prototype.getTab = function(i) {
211
- return $(this.tabs()[i]);
212
- };
213
-
214
- MailCatcher.prototype.selectedTab = function() {
215
- return this.tabs().index($('#message li.tab.selected'));
216
- };
217
-
218
- MailCatcher.prototype.openTab = function(i) {
219
- return this.getTab(i).children('a').click();
220
- };
221
-
222
- MailCatcher.prototype.previousTab = function(tab) {
223
- var i;
224
- i = tab || tab === 0 ? tab : this.selectedTab() - 1;
225
- if (i < 0) {
226
- i = this.tabs().length - 1;
227
- }
228
- if (this.getTab(i).is(":visible")) {
229
- return i;
230
- } else {
231
- return this.previousTab(i - 1);
232
- }
233
- };
234
-
235
- MailCatcher.prototype.nextTab = function(tab) {
236
- var i;
237
- i = tab ? tab : this.selectedTab() + 1;
238
- if (i > this.tabs().length - 1) {
239
- i = 0;
240
- }
241
- if (this.getTab(i).is(":visible")) {
242
- return i;
243
- } else {
244
- return this.nextTab(i + 1);
245
- }
246
- };
247
-
248
- MailCatcher.prototype.haveMessage = function(message) {
249
- if (message.id != null) {
250
- message = message.id;
251
- }
252
- return $("#messages tbody tr[data-message-id=\"" + message + "\"]").length > 0;
253
- };
254
-
255
- MailCatcher.prototype.selectedMessage = function() {
256
- return $('#messages tr.selected').data('message-id');
257
- };
258
-
259
- MailCatcher.prototype.searchMessages = function(query) {
260
- var $rows, selector, token;
261
- selector = ((function() {
262
- var _i, _len, _ref, _results;
263
- _ref = query.split(/\s+/);
264
- _results = [];
265
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
266
- token = _ref[_i];
267
- _results.push(":icontains('" + token + "')");
268
- }
269
- return _results;
270
- })()).join("");
271
- $rows = $("#messages tbody tr");
272
- $rows.not(selector).hide();
273
- return $rows.filter(selector).show();
274
- };
275
-
276
- MailCatcher.prototype.clearSearch = function() {
277
- return $('#messages tbody tr').show();
278
- };
279
-
280
- MailCatcher.prototype.addMessage = function(message) {
281
- return $('#messages tbody').prepend($('<tr />').attr('data-message-id', message.id.toString())).append($('<td/>').text(message.sender || "No sender").toggleClass("blank", !message.sender)).append($('<td/>').text((message.recipients || []).join(', ') || "No recipients").toggleClass("blank", !message.recipients.length)).append($('<td/>').text(message.subject || "No subject").toggleClass("blank", !message.subject)).append($('<td/>').text(this.formatDate(message.created_at)));
282
- };
283
-
284
- MailCatcher.prototype.scrollToRow = function(row) {
285
- var overflow, relativePosition;
286
- relativePosition = row.offset().top - $('#messages').offset().top;
287
- if (relativePosition < 0) {
288
- return $('#messages').scrollTop($('#messages').scrollTop() + relativePosition - 20);
289
- } else {
290
- overflow = relativePosition + row.height() - $('#messages').height();
291
- if (overflow > 0) {
292
- return $('#messages').scrollTop($('#messages').scrollTop() + overflow + 20);
293
- }
294
- }
295
- };
296
-
297
- MailCatcher.prototype.unselectMessage = function() {
298
- $('#messages tbody, #message .metadata dd').empty();
299
- $('#message .metadata .attachments').hide();
300
- $('#message iframe').attr('src', 'about:blank');
301
- return null;
302
- };
303
-
304
- MailCatcher.prototype.loadMessage = function(id) {
305
- var messageRow;
306
- if ((id != null ? id.id : void 0) != null) {
307
- id = id.id;
308
- }
309
- id || (id = $('#messages tr.selected').attr('data-message-id'));
310
- if (id != null) {
311
- $("#messages tbody tr:not([data-message-id='" + id + "'])").removeClass('selected');
312
- messageRow = $("#messages tbody tr[data-message-id='" + id + "']");
313
- messageRow.addClass('selected');
314
- this.scrollToRow(messageRow);
315
- return $.getJSON("/messages/" + id + ".json", (function(_this) {
316
- return function(message) {
317
- var $ul;
318
- if (message.recipients != null) {
319
- message.recipients = JSON.parse(message.recipients);
320
- }
321
- $('#message .metadata dd.created_at').text(_this.formatDate(message.created_at));
322
- $('#message .metadata dd.from').text(message.sender);
323
- $('#message .metadata dd.to').text((message.recipients || []).join(', '));
324
- $('#message .metadata dd.subject').text(message.subject);
325
- $('#message .views .tab.format').each(function(i, el) {
326
- var $el, format;
327
- $el = $(el);
328
- format = $el.attr('data-message-format');
329
- if ($.inArray(format, message.formats) >= 0) {
330
- $el.find('a').attr('href', "/messages/" + id + "." + format);
331
- return $el.show();
332
- } else {
333
- return $el.hide();
334
- }
335
- });
336
- if ($("#message .views .tab.selected:not(:visible)").length) {
337
- $("#message .views .tab.selected").removeClass("selected");
338
- $("#message .views .tab:visible:first").addClass("selected");
339
- }
340
- if (message.attachments.length) {
341
- $ul = $('<ul/>').appendTo($('#message .metadata dd.attachments').empty());
342
- $.each(message.attachments, function(i, attachment) {
343
- return $ul.append($('<li>').append($('<a>').attr('href', attachment['href']).addClass(attachment['type'].split('/', 1)[0]).addClass(attachment['type'].replace('/', '-')).text(attachment['filename'])));
344
- });
345
- $('#message .metadata .attachments').show();
346
- } else {
347
- $('#message .metadata .attachments').hide();
348
- }
349
- $('#message .views .download a').attr('href', "/messages/" + id + ".eml");
350
- if ($('#message .views .tab.analysis.selected').length) {
351
- return _this.loadMessageAnalysis();
352
- } else {
353
- return _this.loadMessageBody();
354
- }
355
- };
356
- })(this));
357
- }
358
- };
359
-
360
- MailCatcher.prototype.loadMessageBody = function(id, format) {
361
- var app;
362
- id || (id = this.selectedMessage());
363
- format || (format = $('#message .views .tab.format.selected').attr('data-message-format'));
364
- format || (format = 'html');
365
- $("#message .views .tab[data-message-format=\"" + format + "\"]:not(.selected)").addClass('selected');
366
- $("#message .views .tab:not([data-message-format=\"" + format + "\"]).selected").removeClass('selected');
367
- if (id != null) {
368
- $('#message iframe').attr("src", "/messages/" + id + "." + format);
369
- return app = this;
370
- }
371
- };
372
-
373
- MailCatcher.prototype.decorateMessageBody = function() {
374
- var body, format, message_iframe, text;
375
- format = $('#message .views .tab.format.selected').attr('data-message-format');
376
- switch (format) {
377
- case 'html':
378
- body = $('#message iframe').contents().find('body');
379
- return $("a", body).attr("target", "_blank");
380
- case 'plain':
381
- message_iframe = $('#message iframe').contents();
382
- text = message_iframe.text();
383
- text = text.replace(/((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:\/~\+#]*[\w\-\@?^=%&amp;\/~\+#])?)/g, '<a href="$1" target="_blank">$1</a>');
384
- text = text.replace(/\n/g, '<br/>');
385
- return message_iframe.find('html').html('<html><body>' + text + '</html></body>');
386
- }
387
- };
388
-
389
- MailCatcher.prototype.loadMessageAnalysis = function(id) {
390
- var $form, $iframe;
391
- id || (id = this.selectedMessage());
392
- $("#message .views .analysis.tab:not(.selected)").addClass('selected');
393
- $("#message .views :not(.analysis).tab.selected").removeClass('selected');
394
- if (id != null) {
395
- $iframe = $('#message iframe').contents().children().html("<html>\n<head>\n<title>Analysis</title>\n" + ($('link[rel="stylesheet"]')[0].outerHTML) + "\n</head>\n<body class=\"iframe\">\n<h1>Analyse your email with Fractal</h1>\n<p><a href=\"http://getfractal.com/\" target=\"_blank\">Fractal</a> is a really neat service that applies common email design and development knowledge from <a href=\"http://www.email-standards.org/\" target=\"_blank\">Email Standards Project</a> to your HTML email and tells you what you've done wrong or what you should do instead.</p>\n<p>Please note that this <strong>sends your email to the Fractal service</strong> for analysis. Read their <a href=\"https://www.getfractal.com/page/terms\" target=\"_blank\">terms of service</a> if you're paranoid.</p>\n<form>\n<input type=\"submit\" value=\"Analyse\" /><span class=\"loading\" style=\"color: #999; display: none\">Analysing&hellip;</span>\n</form>\n</body>\n</html>");
396
- return $form = $iframe.find('form').submit(function(e) {
397
- e.preventDefault();
398
- $(this).find('input[type="submit"]').attr('disabled', 'disabled').end().find('.loading').show();
399
- return $('#message iframe').contents().find('body').xslt("/messages/" + id + "/analysis.xml", "/stylesheets/analysis.xsl");
400
- });
401
- }
402
- };
403
-
404
- MailCatcher.prototype.refresh = function() {
405
- return $.getJSON('/messages', (function(_this) {
406
- return function(messages) {
407
- return $.each(messages, function(i, message) {
408
- if (!_this.haveMessage(message)) {
409
- if (message.recipients != null) {
410
- message.recipients = JSON.parse(message.recipients);
411
- }
412
- return _this.addMessage(message);
413
- }
414
- });
415
- };
416
- })(this));
417
- };
418
-
419
- MailCatcher.prototype.subscribe = function() {
420
- if (typeof WebSocket !== "undefined" && WebSocket !== null) {
421
-
422
- } else {
423
- return this.subscribePoll();
424
- }
425
- };
426
-
427
- MailCatcher.prototype.subscribeWebSocket = function() {
428
- var secure;
429
- secure = window.location.scheme === 'https';
430
- this.websocket = new WebSocket("" + (secure ? 'wss' : 'ws') + "://" + window.location.host + "/messages");
431
- return this.websocket.onmessage = (function(_this) {
432
- return function(event) {
433
- return _this.addMessage($.parseJSON(event.data));
434
- };
435
- })(this);
436
- };
437
-
438
- MailCatcher.prototype.subscribePoll = function() {
439
- if (this.refreshInterval == null) {
440
- return this.refreshInterval = setInterval(((function(_this) {
441
- return function() {
442
- return _this.refresh();
443
- };
444
- })(this)), 1000);
445
- }
446
- };
447
-
448
- MailCatcher.prototype.resizeToSavedKey = 'mailcatcherSeparatorHeight';
449
-
450
- MailCatcher.prototype.resizeTo = function(height) {
451
- var _ref;
452
- $('#messages').css({
453
- height: height - $('#messages').offset().top
454
- });
455
- return (_ref = window.localStorage) != null ? _ref.setItem(this.resizeToSavedKey, height) : void 0;
456
- };
457
-
458
- MailCatcher.prototype.resizeToSaved = function() {
459
- var height, _ref;
460
- height = parseInt((_ref = window.localStorage) != null ? _ref.getItem(this.resizeToSavedKey) : void 0);
461
- if (!isNaN(height)) {
462
- return this.resizeTo(height);
463
- }
464
- };
465
-
466
- return MailCatcher;
467
-
468
- })();
469
-
470
- $(function() {
471
- return window.MailCatcher = new MailCatcher;
472
- });
473
-
474
- }).call(this);
1
+ (function() {
2
+ var MailCatcher,
3
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
4
+
5
+ jQuery.expr[':'].icontains = function(a, i, m) {
6
+ var _ref, _ref1;
7
+ return ((_ref = (_ref1 = a.textContent) != null ? _ref1 : a.innerText) != null ? _ref : "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
8
+ };
9
+
10
+ MailCatcher = (function() {
11
+ function MailCatcher() {
12
+ this.nextTab = __bind(this.nextTab, this);
13
+ this.previousTab = __bind(this.previousTab, this);
14
+ this.openTab = __bind(this.openTab, this);
15
+ this.selectedTab = __bind(this.selectedTab, this);
16
+ this.getTab = __bind(this.getTab, this);
17
+ var _this = this;
18
+ $('#messages tr').live('click', function(e) {
19
+ e.preventDefault();
20
+ return _this.loadMessage($(e.currentTarget).attr('data-message-id'));
21
+ });
22
+ $('input[name=search]').keyup(function(e) {
23
+ var query;
24
+ query = $.trim($(e.currentTarget).val());
25
+ if (query) {
26
+ return _this.searchMessages(query);
27
+ } else {
28
+ return _this.clearSearch();
29
+ }
30
+ });
31
+ $('#message .views .format.tab a').live('click', function(e) {
32
+ e.preventDefault();
33
+ return _this.loadMessageBody(_this.selectedMessage(), $($(e.currentTarget).parent('li')).data('message-format'));
34
+ });
35
+ $('#message .views .analysis.tab a').live('click', function(e) {
36
+ e.preventDefault();
37
+ return _this.loadMessageAnalysis(_this.selectedMessage());
38
+ });
39
+ $('#message iframe').load(function() {
40
+ return _this.decorateMessageBody();
41
+ });
42
+ $('#resizer').live({
43
+ mousedown: function(e) {
44
+ var events;
45
+ e.preventDefault();
46
+ return $(window).bind(events = {
47
+ mouseup: function(e) {
48
+ e.preventDefault();
49
+ return $(window).unbind(events);
50
+ },
51
+ mousemove: function(e) {
52
+ e.preventDefault();
53
+ return _this.resizeTo(e.clientY);
54
+ }
55
+ });
56
+ }
57
+ });
58
+ this.resizeToSaved();
59
+ $('nav.app .clear a').live('click', function(e) {
60
+ e.preventDefault();
61
+ if (confirm("You will lose all your received messages.\n\nAre you sure you want to clear all messages?")) {
62
+ return $.ajax({
63
+ url: '/messages',
64
+ type: 'DELETE',
65
+ success: function() {
66
+ return _this.unselectMessage();
67
+ },
68
+ error: function() {
69
+ return alert('Error while clearing all messages.');
70
+ }
71
+ });
72
+ }
73
+ });
74
+ $('nav.app .quit a').live('click', function(e) {
75
+ e.preventDefault();
76
+ if (confirm("You will lose all your received messages.\n\nAre you sure you want to quit?")) {
77
+ return $.ajax({
78
+ type: 'DELETE',
79
+ success: function() {
80
+ return location.replace($('body > header h1 a').attr('href'));
81
+ },
82
+ error: function() {
83
+ return alert('Error while quitting.');
84
+ }
85
+ });
86
+ }
87
+ });
88
+ key('up', function() {
89
+ if (_this.selectedMessage()) {
90
+ _this.loadMessage($('#messages tr.selected').prev().data('message-id'));
91
+ } else {
92
+ _this.loadMessage($('#messages tbody tr[data-message-id]:first').data('message-id'));
93
+ }
94
+ return false;
95
+ });
96
+ key('down', function() {
97
+ if (_this.selectedMessage()) {
98
+ _this.loadMessage($('#messages tr.selected').next().data('message-id'));
99
+ } else {
100
+ _this.loadMessage($('#messages tbody tr[data-message-id]:first').data('message-id'));
101
+ }
102
+ return false;
103
+ });
104
+ key('Γîÿ+up, ctrl+up', function() {
105
+ _this.loadMessage($('#messages tbody tr[data-message-id]:first').data('message-id'));
106
+ return false;
107
+ });
108
+ key('Γîÿ+down, ctrl+down', function() {
109
+ _this.loadMessage($('#messages tbody tr[data-message-id]:last').data('message-id'));
110
+ return false;
111
+ });
112
+ key('left', function() {
113
+ _this.openTab(_this.previousTab());
114
+ return false;
115
+ });
116
+ key('right', function() {
117
+ _this.openTab(_this.nextTab());
118
+ return false;
119
+ });
120
+ key('backspace, delete', function() {
121
+ var id;
122
+ id = _this.selectedMessage();
123
+ if (id != null) {
124
+ $.ajax({
125
+ url: '/messages/' + id,
126
+ type: 'DELETE',
127
+ success: function() {
128
+ var messageRow, switchTo;
129
+ messageRow = $("#messages tbody tr[data-message-id='" + id + "']");
130
+ switchTo = messageRow.next().data('message-id') || messageRow.prev().data('message-id');
131
+ messageRow.remove();
132
+ if (switchTo) {
133
+ return _this.loadMessage(switchTo);
134
+ } else {
135
+ return _this.unselectMessage();
136
+ }
137
+ },
138
+ error: function() {
139
+ return alert('Error while removing message.');
140
+ }
141
+ });
142
+ }
143
+ return false;
144
+ });
145
+ this.refresh();
146
+ this.subscribe();
147
+ }
148
+
149
+ MailCatcher.prototype.parseDateRegexp = /^(\d{4})[-\/\\](\d{2})[-\/\\](\d{2})(?:\s+|T)(\d{2})[:-](\d{2})[:-](\d{2})(?:([ +-]\d{2}:\d{2}|\s*\S+|Z?))?$/;
150
+
151
+ MailCatcher.prototype.parseDate = function(date) {
152
+ var match;
153
+ if (match = this.parseDateRegexp.exec(date)) {
154
+ return new Date(match[1], match[2] - 1, match[3], match[4], match[5], match[6], 0);
155
+ }
156
+ };
157
+
158
+ MailCatcher.prototype.offsetTimeZone = function(date) {
159
+ var offset;
160
+ offset = Date.now().getTimezoneOffset() * 60000;
161
+ date.setTime(date.getTime() - offset);
162
+ return date;
163
+ };
164
+
165
+ MailCatcher.prototype.formatDate = function(date) {
166
+ if (typeof date === "string") {
167
+ date && (date = this.parseDate(date));
168
+ }
169
+ date && (date = this.offsetTimeZone(date));
170
+ return date && (date = date.toString("dddd, d MMM yyyy h:mm:ss tt"));
171
+ };
172
+
173
+ MailCatcher.prototype.messagesCount = function() {
174
+ return $('#messages tr').length - 1;
175
+ };
176
+
177
+ MailCatcher.prototype.tabs = function() {
178
+ return $('#message ul').children('.tab');
179
+ };
180
+
181
+ MailCatcher.prototype.getTab = function(i) {
182
+ return $(this.tabs()[i]);
183
+ };
184
+
185
+ MailCatcher.prototype.selectedTab = function() {
186
+ return this.tabs().index($('#message li.tab.selected'));
187
+ };
188
+
189
+ MailCatcher.prototype.openTab = function(i) {
190
+ return this.getTab(i).children('a').click();
191
+ };
192
+
193
+ MailCatcher.prototype.previousTab = function(tab) {
194
+ var i;
195
+ i = tab || tab === 0 ? tab : this.selectedTab() - 1;
196
+ if (i < 0) {
197
+ i = this.tabs().length - 1;
198
+ }
199
+ if (this.getTab(i).is(":visible")) {
200
+ return i;
201
+ } else {
202
+ return this.previousTab(i - 1);
203
+ }
204
+ };
205
+
206
+ MailCatcher.prototype.nextTab = function(tab) {
207
+ var i;
208
+ i = tab ? tab : this.selectedTab() + 1;
209
+ if (i > this.tabs().length - 1) {
210
+ i = 0;
211
+ }
212
+ if (this.getTab(i).is(":visible")) {
213
+ return i;
214
+ } else {
215
+ return this.nextTab(i + 1);
216
+ }
217
+ };
218
+
219
+ MailCatcher.prototype.haveMessage = function(message) {
220
+ if (message.id != null) {
221
+ message = message.id;
222
+ }
223
+ return $("#messages tbody tr[data-message-id=\"" + message + "\"]").length > 0;
224
+ };
225
+
226
+ MailCatcher.prototype.selectedMessage = function() {
227
+ return $('#messages tr.selected').data('message-id');
228
+ };
229
+
230
+ MailCatcher.prototype.searchMessages = function(query) {
231
+ var $rows, selector, token;
232
+ selector = ((function() {
233
+ var _i, _len, _ref, _results;
234
+ _ref = query.split(/\s+/);
235
+ _results = [];
236
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
237
+ token = _ref[_i];
238
+ _results.push(":icontains('" + token + "')");
239
+ }
240
+ return _results;
241
+ })()).join("");
242
+ $rows = $("#messages tbody tr");
243
+ $rows.not(selector).hide();
244
+ return $rows.filter(selector).show();
245
+ };
246
+
247
+ MailCatcher.prototype.clearSearch = function() {
248
+ return $('#messages tbody tr').show();
249
+ };
250
+
251
+ MailCatcher.prototype.addMessage = function(message) {
252
+ return $('#messages tbody').prepend($('<tr />').attr('data-message-id', message.id.toString()).append($('<td/>').text(message.sender || "No sender").toggleClass("blank", !message.sender)).append($('<td/>').text((message.recipients || []).join(', ') || "No recipients").toggleClass("blank", !message.recipients.length)).append($('<td/>').text(message.subject || "No subject").toggleClass("blank", !message.subject)).append($('<td/>').text(this.formatDate(message.created_at))));
253
+ };
254
+
255
+ MailCatcher.prototype.scrollToRow = function(row) {
256
+ var overflow, relativePosition;
257
+ relativePosition = row.offset().top - $('#messages').offset().top;
258
+ if (relativePosition < 0) {
259
+ return $('#messages').scrollTop($('#messages').scrollTop() + relativePosition - 20);
260
+ } else {
261
+ overflow = relativePosition + row.height() - $('#messages').height();
262
+ if (overflow > 0) {
263
+ return $('#messages').scrollTop($('#messages').scrollTop() + overflow + 20);
264
+ }
265
+ }
266
+ };
267
+
268
+ MailCatcher.prototype.unselectMessage = function() {
269
+ $('#messages tbody, #message .metadata dd').empty();
270
+ $('#message .metadata .attachments').hide();
271
+ $('#message iframe').attr('src', 'about:blank');
272
+ return null;
273
+ };
274
+
275
+ MailCatcher.prototype.loadMessage = function(id) {
276
+ var messageRow,
277
+ _this = this;
278
+ if ((id != null ? id.id : void 0) != null) {
279
+ id = id.id;
280
+ }
281
+ id || (id = $('#messages tr.selected').attr('data-message-id'));
282
+ if (id != null) {
283
+ $("#messages tbody tr:not([data-message-id='" + id + "'])").removeClass('selected');
284
+ messageRow = $("#messages tbody tr[data-message-id='" + id + "']");
285
+ messageRow.addClass('selected');
286
+ this.scrollToRow(messageRow);
287
+ return $.getJSON("/messages/" + id + ".json", function(message) {
288
+ var $ul;
289
+ if (message.recipients != null) {
290
+ message.recipients = JSON.parse(message.recipients);
291
+ }
292
+ $('#message .metadata dd.created_at').text(_this.formatDate(message.created_at));
293
+ $('#message .metadata dd.from').text(message.sender);
294
+ $('#message .metadata dd.to').text((message.recipients || []).join(', '));
295
+ $('#message .metadata dd.subject').text(message.subject);
296
+ $('#message .views .tab.format').each(function(i, el) {
297
+ var $el, format;
298
+ $el = $(el);
299
+ format = $el.attr('data-message-format');
300
+ if ($.inArray(format, message.formats) >= 0) {
301
+ $el.find('a').attr('href', "/messages/" + id + "." + format);
302
+ return $el.show();
303
+ } else {
304
+ return $el.hide();
305
+ }
306
+ });
307
+ if ($("#message .views .tab.selected:not(:visible)").length) {
308
+ $("#message .views .tab.selected").removeClass("selected");
309
+ $("#message .views .tab:visible:first").addClass("selected");
310
+ }
311
+ if (message.attachments.length) {
312
+ $ul = $('<ul/>').appendTo($('#message .metadata dd.attachments').empty());
313
+ $.each(message.attachments, function(i, attachment) {
314
+ return $ul.append($('<li>').append($('<a>').attr('href', attachment['href']).addClass(attachment['type'].split('/', 1)[0]).addClass(attachment['type'].replace('/', '-')).text(attachment['filename'])));
315
+ });
316
+ $('#message .metadata .attachments').show();
317
+ } else {
318
+ $('#message .metadata .attachments').hide();
319
+ }
320
+ $('#message .views .download a').attr('href', "/messages/" + id + ".eml");
321
+ if ($('#message .views .tab.analysis.selected').length) {
322
+ return _this.loadMessageAnalysis();
323
+ } else {
324
+ return _this.loadMessageBody();
325
+ }
326
+ });
327
+ }
328
+ };
329
+
330
+ MailCatcher.prototype.loadMessageBody = function(id, format) {
331
+ var app;
332
+ id || (id = this.selectedMessage());
333
+ format || (format = $('#message .views .tab.format.selected').attr('data-message-format'));
334
+ format || (format = 'html');
335
+ $("#message .views .tab[data-message-format=\"" + format + "\"]:not(.selected)").addClass('selected');
336
+ $("#message .views .tab:not([data-message-format=\"" + format + "\"]).selected").removeClass('selected');
337
+ if (id != null) {
338
+ $('#message iframe').attr("src", "/messages/" + id + "." + format);
339
+ return app = this;
340
+ }
341
+ };
342
+
343
+ MailCatcher.prototype.decorateMessageBody = function() {
344
+ var body, format, message_iframe, text;
345
+ format = $('#message .views .tab.format.selected').attr('data-message-format');
346
+ switch (format) {
347
+ case 'html':
348
+ body = $('#message iframe').contents().find('body');
349
+ return $("a", body).attr("target", "_blank");
350
+ case 'plain':
351
+ message_iframe = $('#message iframe').contents();
352
+ text = message_iframe.text();
353
+ text = text.replace(/((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:\/~\+#]*[\w\-\@?^=%&amp;\/~\+#])?)/g, '<a href="$1" target="_blank">$1</a>');
354
+ text = text.replace(/\n/g, '<br/>');
355
+ return message_iframe.find('html').html('<html><body>' + text + '</html></body>');
356
+ }
357
+ };
358
+
359
+ MailCatcher.prototype.loadMessageAnalysis = function(id) {
360
+ var $form, $iframe;
361
+ id || (id = this.selectedMessage());
362
+ $("#message .views .analysis.tab:not(.selected)").addClass('selected');
363
+ $("#message .views :not(.analysis).tab.selected").removeClass('selected');
364
+ if (id != null) {
365
+ $iframe = $('#message iframe').contents().children().html("<html>\n<head>\n<title>Analysis</title>\n" + ($('link[rel="stylesheet"]')[0].outerHTML) + "\n</head>\n<body class=\"iframe\">\n<h1>Analyse your email with Fractal</h1>\n<p><a href=\"http://getfractal.com/\" target=\"_blank\">Fractal</a> is a really neat service that applies common email design and development knowledge from <a href=\"http://www.email-standards.org/\" target=\"_blank\">Email Standards Project</a> to your HTML email and tells you what you've done wrong or what you should do instead.</p>\n<p>Please note that this <strong>sends your email to the Fractal service</strong> for analysis. Read their <a href=\"https://www.getfractal.com/page/terms\" target=\"_blank\">terms of service</a> if you're paranoid.</p>\n<form>\n<input type=\"submit\" value=\"Analyse\" /><span class=\"loading\" style=\"color: #999; display: none\">Analysing&hellip;</span>\n</form>\n</body>\n</html>");
366
+ return $form = $iframe.find('form').submit(function(e) {
367
+ e.preventDefault();
368
+ $(this).find('input[type="submit"]').attr('disabled', 'disabled').end().find('.loading').show();
369
+ return $('#message iframe').contents().find('body').xslt("/messages/" + id + "/analysis.xml", "/stylesheets/analysis.xsl");
370
+ });
371
+ }
372
+ };
373
+
374
+ MailCatcher.prototype.refresh = function() {
375
+ var _this = this;
376
+ return $.getJSON('/messages', function(messages) {
377
+ return $.each(messages, function(i, message) {
378
+ if (!_this.haveMessage(message)) {
379
+ if (message.recipients != null) {
380
+ message.recipients = JSON.parse(message.recipients);
381
+ }
382
+ return _this.addMessage(message);
383
+ }
384
+ });
385
+ });
386
+ };
387
+
388
+ MailCatcher.prototype.subscribe = function() {
389
+ if (typeof WebSocket !== "undefined" && WebSocket !== null) {
390
+
391
+ } else {
392
+ return this.subscribePoll();
393
+ }
394
+ };
395
+
396
+ MailCatcher.prototype.subscribeWebSocket = function() {
397
+ var secure,
398
+ _this = this;
399
+ secure = window.location.scheme === 'https';
400
+ this.websocket = new WebSocket("" + (secure ? 'wss' : 'ws') + "://" + window.location.host + "/messages");
401
+ return this.websocket.onmessage = function(event) {
402
+ return _this.addMessage($.parseJSON(event.data));
403
+ };
404
+ };
405
+
406
+ MailCatcher.prototype.subscribePoll = function() {
407
+ var _this = this;
408
+ if (this.refreshInterval == null) {
409
+ return this.refreshInterval = setInterval((function() {
410
+ return _this.refresh();
411
+ }), 1000);
412
+ }
413
+ };
414
+
415
+ MailCatcher.prototype.resizeToSavedKey = 'mailcatcherSeparatorHeight';
416
+
417
+ MailCatcher.prototype.resizeTo = function(height) {
418
+ var _ref;
419
+ $('#messages').css({
420
+ height: height - $('#messages').offset().top
421
+ });
422
+ return (_ref = window.localStorage) != null ? _ref.setItem(this.resizeToSavedKey, height) : void 0;
423
+ };
424
+
425
+ MailCatcher.prototype.resizeToSaved = function() {
426
+ var height, _ref;
427
+ height = parseInt((_ref = window.localStorage) != null ? _ref.getItem(this.resizeToSavedKey) : void 0);
428
+ if (!isNaN(height)) {
429
+ return this.resizeTo(height);
430
+ }
431
+ };
432
+
433
+ return MailCatcher;
434
+
435
+ })();
436
+
437
+ $(function() {
438
+ return window.MailCatcher = new MailCatcher;
439
+ });
440
+
441
+ }).call(this);