mailcatcher-jruby 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 08d2302a67b12fe5f7526c85990fdd00dc36f09d
4
- data.tar.gz: a8b507672ac95619a351250630b58e17ebf06a13
3
+ metadata.gz: 0b12132d30e684f47cc6409c240b0684615fb436
4
+ data.tar.gz: 11958f289b65ecf2f04958d1a9a05eaa3813392c
5
5
  SHA512:
6
- metadata.gz: 45dad7c9b750c0f9f65c4f64666c9ef11a17c2a6449e1ed4ca2a24dc93ca2e089b8387d477b2ece2b6b269ae8454999c36d8ee5ef2d2a4d0ce46ce0579bcda82
7
- data.tar.gz: 2bb109596422c4eb875ef6846602c1f09d4b20976743ee98a1e6f9b9707c80086b18ff63a562f0e2b5861a889fe84d09d02ada267f3a2bbb5e2feb44affde68b
6
+ metadata.gz: 6027fc8fdb637e18dcc60a37973dd16bf9a7942c17f25e453e669cda48881ba92e9fa7f13366e1dfe7a4501a15c8d422bb0cc4571abe643cc79df00d867d5502
7
+ data.tar.gz: 7cf61262e58f58ed09b76bb4ed9a493bb34c827280c83fb457201c9e2e98735917b86c9c646991448fe48fcb58de0ee2130bd5773af88723aa4fe1935319910a
@@ -1,16 +1,16 @@
1
1
  require 'active_support/json'
2
2
  require 'active_record'
3
3
  require 'mail'
4
- #require 'sqlite3'
5
4
  require 'eventmachine'
6
5
  require 'tmpdir'
7
6
 
8
7
  db_path = File.join(Dir::tmpdir, 'mailcatcherdb')
9
8
 
10
- ActiveRecord::Base.configurations["db"] = { adapter: 'jdbcsqlite3', database: db_path, pool: 20 }
9
+ #ActiveRecord::Base.configurations["db"] = { adapter: 'jdbcsqlite3', database: db_path, pool: 5 }
10
+ ActiveRecord::Base.establish_connection({ adapter: 'jdbcsqlite3', database: db_path, pool: 5 })
11
11
 
12
12
  class Message < ActiveRecord::Base
13
- establish_connection :db
13
+ #establish_connection :db
14
14
  has_many :message_parts, dependent: :destroy
15
15
  self.inheritance_column = nil
16
16
 
@@ -19,7 +19,7 @@ class Message < ActiveRecord::Base
19
19
  end
20
20
  end
21
21
  class MessagePart < ActiveRecord::Base
22
- establish_connection :db
22
+ #establish_connection :db
23
23
  belongs_to :message
24
24
  self.inheritance_column = nil
25
25
  end
@@ -50,10 +50,8 @@ end unless MessagePart.table_exists?
50
50
  module MailCatcher::Mail extend self
51
51
 
52
52
  def add_message(message)
53
- #@add_message_query ||= db.prepare("INSERT INTO message (sender, recipients, subject, source, type, size, created_at) VALUES (?, ?, ?, ?, ?, ?, datetime('now'))")
54
53
 
55
54
  mail = Mail.new(message[:source])
56
- #@add_message_query.execute(message[:sender], message[:recipients].to_json, mail.subject, message[:source], mail.mime_type || 'text/plain', message[:source].length)
57
55
 
58
56
  m = Message.create(
59
57
  sender: message[:sender],
@@ -72,7 +70,6 @@ module MailCatcher::Mail extend self
72
70
  body = part.body.to_s
73
71
  # Only parts have CIDs, not mail
74
72
  cid = part.cid if part.respond_to? :cid
75
- #add_message_part(message_id, cid, part.mime_type || 'text/plain', part.attachment? ? 1 : 0, part.filename, part.charset, body, body.length)
76
73
  MessagePart.create(
77
74
  message_id: message_id,
78
75
  cid: cid,
@@ -91,77 +88,38 @@ module MailCatcher::Mail extend self
91
88
  end
92
89
  end
93
90
 
94
- #def add_message_part(*args)
95
- #@add_message_part_query ||= db.prepare "INSERT INTO message_part (message_id, cid, type, is_attachment, filename, charset, body, size, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))"
96
- #@add_message_part_query.execute(*args)
97
- #end
98
-
99
- #def latest_created_at
100
- #@latest_created_at_query ||= db.prepare "SELECT created_at FROM message ORDER BY created_at DESC LIMIT 1"
101
- #@latest_created_at_query.execute.next
102
- #end
103
-
104
91
  def messages
105
92
  Message.all.map(&:attributes)
106
- #@messages_query ||= db.prepare "SELECT id, sender, recipients, subject, size, created_at FROM message ORDER BY created_at ASC"
107
- #@messages_query.execute.map do |row|
108
- #Hash[row.fields.zip(row)].tap do |message|
109
- #message["recipients"] &&= ActiveSupport::JSON.decode message["recipients"]
110
- #end
111
- #end
112
93
  end
113
94
 
114
95
  def message(id)
115
96
  Message.find(id).attributes
116
- #@message_query ||= db.prepare "SELECT * FROM message WHERE id = ? LIMIT 1"
117
- #row = @message_query.execute(id).next
118
- #row && Hash[row.fields.zip(row)].tap do |message|
119
- #message["recipients"] &&= ActiveSupport::JSON.decode message["recipients"]
120
- #end
121
97
  end
122
98
 
123
99
  def message_has_html?(id)
124
100
  part = MessagePart.where(message_id: id, is_attachment: 0).where("type IN ('application/xhtml+xml', 'text/html')").first
125
101
  part.present? || ['text/html', 'application/xhtml+xml'].include?(Message.find(id).type)
126
- #@message_has_html_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type IN ('application/xhtml+xml', 'text/html') LIMIT 1"
127
- #(!!@message_has_html_query.execute(id).next) || ['text/html', 'application/xhtml+xml'].include?(message(id)["type"])
128
102
  end
129
103
 
130
104
  def message_has_plain?(id)
131
105
  part = MessagePart.where(message_id: id, is_attachment: 0, type: 'text/plain').first
132
106
  part.present? || Message.find(id).type == 'text/plain'
133
- #@message_has_plain_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type = 'text/plain' LIMIT 1"
134
- #(!!@message_has_plain_query.execute(id).next) || message(id)["type"] == "text/plain"
135
107
  end
136
108
 
137
109
  def message_parts(id)
138
110
  MessagePart.where(:message_id => id).order('filename ASC').map(&:attributes)
139
- #@message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? ORDER BY filename ASC"
140
- #@message_parts_query.execute(id).map do |row|
141
- #Hash[row.fields.zip(row)]
142
- #end
143
111
  end
144
112
 
145
113
  def message_attachments(id)
146
114
  MessagePart.where(message_id: id, is_attachment: 1).order('filename ASC').map(&:attributes)
147
- #@message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? AND is_attachment = 1 ORDER BY filename ASC"
148
- #@message_parts_query.execute(id).map do |row|
149
- #Hash[row.fields.zip(row)]
150
- #end
151
115
  end
152
116
 
153
117
  def message_part(message_id, part_id)
154
118
  MessagePart.where(message_id: message_id, id: part_id).first.try(:attributes)
155
- #@message_part_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND id = ? LIMIT 1"
156
- #row = @message_part_query.execute(message_id, part_id).next
157
- #row && Hash[row.fields.zip(row)]
158
119
  end
159
120
 
160
121
  def message_part_type(message_id, part_type)
161
122
  MessagePart.where(message_id: message_id, type: part_type, is_attachment: 0).first.try(:attributes)
162
- #@message_part_type_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND type = ? AND is_attachment = 0 LIMIT 1"
163
- #row = @message_part_type_query.execute(message_id, part_type).next
164
- #row && Hash[row.fields.zip(row)]
165
123
  end
166
124
 
167
125
  def message_part_html(message_id)
@@ -179,28 +137,13 @@ module MailCatcher::Mail extend self
179
137
 
180
138
  def message_part_cid(message_id, cid)
181
139
  MessagePart.where(message_id: message_id, cid: cid).first.try(:attributes)
182
- #@message_part_cid_query ||= db.prepare 'SELECT * FROM message_part WHERE message_id = ?'
183
- #@message_part_cid_query.execute(message_id).map do |row|
184
- #Hash[row.fields.zip(row)]
185
- #end.find do |part|
186
- #part["cid"] == cid
187
- #end
188
140
  end
189
141
 
190
142
  def delete!
191
143
  Message.destroy_all
192
- #@delete_messages_query ||= db.prepare 'DELETE FROM message'
193
- #@delete_message_parts_query ||= db.prepare 'DELETE FROM message_part'
194
-
195
- #@delete_messages_query.execute and
196
- #@delete_message_parts_query.execute
197
144
  end
198
145
 
199
146
  def delete_message!(message_id)
200
147
  Message.where(id: message_id).destroy_all
201
- #@delete_messages_query ||= db.prepare 'DELETE FROM message WHERE id = ?'
202
- #@delete_message_parts_query ||= db.prepare 'DELETE FROM message_part WHERE message_id = ?'
203
- #@delete_messages_query.execute(message_id) and
204
- #@delete_message_parts_query.execute(message_id)
205
148
  end
206
149
  end
@@ -1,3 +1,3 @@
1
1
  module MailCatcher
2
- VERSION = "1.1.3"
2
+ VERSION = "1.1.4"
3
3
  end
@@ -11,6 +11,8 @@ class Sinatra::Request
11
11
  end
12
12
 
13
13
  class MailCatcher::Web < Sinatra::Base
14
+ use ActiveRecord::ConnectionAdapters::ConnectionManagement
15
+
14
16
  set :root, File.expand_path("#{__FILE__}/../../..")
15
17
  set :haml, :format => :html5
16
18
 
@@ -1,441 +1,474 @@
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
- return this.subscribeWebSocket();
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);
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);