mail_grabber 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MailGrabber
4
+ class DeliveryMethod
5
+ include DatabaseHelper
6
+
7
+ # Initialize MailGrabber delivery method (Rails needs it).
8
+ def initialize(options = {}); end
9
+
10
+ # Catch and save messages into the database that we can check those messages
11
+ # in MailGrabber web application.
12
+ #
13
+ # @param [Mail::Message] message what we would like to send
14
+ def deliver!(message)
15
+ unless message.is_a?(Mail::Message)
16
+ raise Error::WrongParameter,
17
+ 'The given parameter is not a Mail::Message'
18
+ end
19
+
20
+ store_mail(message)
21
+ end
22
+
23
+ # Delivery method settings (needed when run mail.deliver! method)
24
+ def settings
25
+ {}
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MailGrabber
4
+ class Error < StandardError
5
+ # Specific error class for errors if database error happen
6
+ class DatabaseHelperError < Error; end
7
+
8
+ # Specific error class for errors if parameter is not given
9
+ class WrongParameter < Error; end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MailGrabber
4
+ class Railtie < Rails::Railtie
5
+ initializer 'mail_grabber.add_delivery_method' do
6
+ ActiveSupport.on_load :action_mailer do
7
+ ActionMailer::Base.add_delivery_method(
8
+ :mail_grabber,
9
+ MailGrabber::DeliveryMethod
10
+ )
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MailGrabber
4
+ VERSION = '1.0.0.rc1'
5
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+ require 'rack'
5
+
6
+ require 'mail_grabber/error'
7
+ require 'mail_grabber/database_helper'
8
+
9
+ require 'mail_grabber/web/application_helper'
10
+ require 'mail_grabber/web/application_router'
11
+ require 'mail_grabber/web/application'
12
+
13
+ module MailGrabber
14
+ module Web
15
+ module_function
16
+
17
+ # Method which build a Rack application and run the Web::Application
18
+ def app
19
+ @app ||= Rack::Builder.new do
20
+ use Rack::Static,
21
+ urls: ['/images', '/javascripts', '/stylesheets'],
22
+ root: File.expand_path('web/assets', __dir__)
23
+
24
+ run Web::Application
25
+ end
26
+ end
27
+
28
+ # Method to call MailGrabber::Web. This method will call the app method
29
+ # above.
30
+ #
31
+ # @param [Hash] env the environment variables
32
+ def call(env)
33
+ app.call(env)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module MailGrabber
6
+ module Web
7
+ class Application
8
+ extend ApplicationRouter
9
+
10
+ include ApplicationHelper
11
+ include DatabaseHelper
12
+
13
+ attr_reader :request, :response
14
+
15
+ # Method to call MailGrabber::Web::Application. This method will call the
16
+ # initialize method and returns back with response of the application.
17
+ #
18
+ # @param [Hash] env the environment variables
19
+ #
20
+ # @return [Array] the response of the web application
21
+ # e.g. [200, {}, ['Hello World']]
22
+ def self.call(env)
23
+ new(env).response.finish
24
+ end
25
+
26
+ # Initialize web application request and response then process the given
27
+ # request.
28
+ #
29
+ # @param [Hash] env the environment variables
30
+ def initialize(env)
31
+ @request = Rack::Request.new(env)
32
+ @response = Rack::Response.new
33
+
34
+ process_request
35
+ end
36
+
37
+ # Extract env['PATH_INFO'] value. If the path info is empty then it will
38
+ # return with root path.
39
+ #
40
+ # @return [String] path the requested path or the root path if this value
41
+ # is empty
42
+ def path
43
+ @path ||= request.path_info.empty? ? '/' : request.path_info
44
+ end
45
+
46
+ # This method returns back with extracted request parameters.
47
+ #
48
+ # @return [Hash] params
49
+ def params
50
+ request.params
51
+ end
52
+
53
+ # Extract env['REQUEST_METHOD'] value.
54
+ #
55
+ # @return [String] request_method with e.g. GET, POST or DELETE etc.
56
+ def request_method
57
+ request.request_method
58
+ end
59
+
60
+ # Extract env['SCRIPT_NAME'] value.
61
+ #
62
+ # @return [String] script_name the initial portion of the request 'path'
63
+ def script_name
64
+ request.script_name
65
+ end
66
+
67
+ # Parse the routes of the ApplicationRouter and tries to find matching
68
+ # route for the request method, which was defined in the
69
+ # get, post, put, patch or delete blocks. If the 'extracted_params' is nil
70
+ # then it could not found any defined routes. If it can find a defined
71
+ # route then it saves the params and call the given block. If it cannot
72
+ # find anything then it will set response with 404 Not Found.
73
+ def process_request
74
+ self.class.routes[request_method].each do |route|
75
+ extracted_params = route.extract_params(path)
76
+
77
+ next unless extracted_params
78
+
79
+ request.update_param('request_params', extracted_params)
80
+
81
+ return instance_exec(&route.block)
82
+ end
83
+
84
+ response.status = 404
85
+ response.write('Not Found')
86
+ end
87
+
88
+ get '/' do
89
+ response.write(render('index.html.erb'))
90
+ end
91
+
92
+ get '/messages.json' do
93
+ result =
94
+ if params['page'].nil? || params['per_page'].nil?
95
+ select_all_messages
96
+ else
97
+ select_messages_by(params['page'], params['per_page'])
98
+ end
99
+
100
+ response.write(result.to_json)
101
+ end
102
+
103
+ get '/message/:id.json' do
104
+ message = select_message_by(params['request_params']['id'])
105
+ message_parts = select_message_parts_by(params['request_params']['id'])
106
+
107
+ response.write(
108
+ { message: message, message_parts: message_parts }.to_json
109
+ )
110
+ end
111
+
112
+ delete '/messages.json' do
113
+ delete_all_messages
114
+
115
+ response.write({ info: 'All messages have been deleted' }.to_json)
116
+ end
117
+
118
+ delete '/message/:id.json' do
119
+ delete_message_by(params['request_params']['id'])
120
+
121
+ response.write({ info: 'Message has been deleted' }.to_json)
122
+ end
123
+
124
+ # Render erb template from the views folder.
125
+ #
126
+ # @param [String] template
127
+ #
128
+ # @return [String] template with the result
129
+ def render(template)
130
+ path = File.expand_path("views/#{template}", __dir__)
131
+ ERB.new(File.read(path)).result(binding)
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MailGrabber
4
+ module Web
5
+ # Helper module for views
6
+ module ApplicationHelper
7
+ # This method helps us that e.g. we can load style or javascript files
8
+ # when we are running this application standalone or in Ruby on Rails.
9
+ def root_path
10
+ script_name.to_s
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MailGrabber
4
+ module Web
5
+ module ApplicationRouter
6
+ NAMED_SEGMENTS_PATTERN = %r{/([^/]*):([^.:$/]+)}.freeze
7
+
8
+ attr_reader :routes
9
+
10
+ Route =
11
+ Struct.new(:pattern, :block) do
12
+ # Extract parameters from the given path. All routes has a
13
+ # path pattern which helps to the router to find which block it should
14
+ # execute. If path contains request parameters like '/test/1' then
15
+ # it will match with the '/test/:id' pattern. In this case it will
16
+ # return with '{"id" => "1"}' hash. If it is just a simple path like
17
+ # '/' and it has a pattern to match then it will return with '{}'.
18
+ # In the other case it will return with nil.
19
+ #
20
+ # @param [String] path
21
+ #
22
+ # @return [Hash/NilClass] with the extracted parameters, empty Hash
23
+ # or nil
24
+ def extract_params(path)
25
+ if pattern.match?(NAMED_SEGMENTS_PATTERN)
26
+ named_pattern =
27
+ pattern.gsub(NAMED_SEGMENTS_PATTERN, '/\1(?<\2>[^$/]+)')
28
+
29
+ path.match(Regexp.new("\\A#{named_pattern}\\Z"))&.named_captures
30
+ elsif path == pattern
31
+ {}
32
+ end
33
+ end
34
+ end
35
+
36
+ # Define route method that we can define routing blocks.
37
+ #
38
+ # @example
39
+ #
40
+ # get '/' do
41
+ # response.write 'Hello MailGrabber'
42
+ # end
43
+ #
44
+ # @example
45
+ #
46
+ # method pattern block
47
+ # | | |
48
+ # get '/test' do ... end
49
+ #
50
+ %w[GET POST PUT PATCH DELETE].each do |method|
51
+ define_method(method.downcase) do |pattern, &block|
52
+ route(method, pattern, &block)
53
+ end
54
+ end
55
+
56
+ # Store routes with the request method, the provided pattern and the given
57
+ # block.
58
+ #
59
+ # @param [String] method e.g. GET, POST etc.
60
+ # @param [String] pattern the path what we are looking for
61
+ # @param [Proc] block what we will run
62
+ def route(method, pattern, &block)
63
+ @routes ||= {}
64
+
65
+ set_route('HEAD', pattern, &block) if method == 'GET'
66
+ set_route(method, pattern, &block)
67
+ end
68
+
69
+ # Set routes Hash with the Route object.
70
+ #
71
+ # @param [String] method e.g. GET, POST etc.
72
+ # @param [String] pattern the path what we are looking for
73
+ # @param [Proc] block what we will run
74
+ def set_route(method, pattern, &block)
75
+ (@routes[method] ||= []) << Route.new(pattern, block)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,539 @@
1
+ (function() {
2
+ var MailGrabber = {
3
+ /**
4
+ * Change which content (message part) should show. When the page is loading
5
+ * the HTML content will be active and the others will be hidden. When we
6
+ * click on tab e.g. Plain Text then this content will active and other
7
+ * hidden.
8
+ *
9
+ * @param {Object} event - which part we clicked
10
+ */
11
+ changeMessageContent: function(event) {
12
+ var messageTabs =
13
+ document
14
+ .querySelectorAll('[data-message-tab]');
15
+
16
+ var messageContents =
17
+ document
18
+ .querySelectorAll('[data-message-content]');
19
+
20
+ var clickedTabType = event.target.dataset.messageTab;
21
+
22
+ messageTabs.forEach(function(messageTab, index) {
23
+ messageTab.classList.remove('active');
24
+ messageContents[index].classList.remove('hide');
25
+
26
+ if(messageTab.dataset.messageTab === clickedTabType) {
27
+ messageTab.classList.add('active');
28
+ }
29
+
30
+ if(messageContents[index].dataset.messageContent !== clickedTabType) {
31
+ messageContents[index].classList.add('hide');
32
+ }
33
+ });
34
+ },
35
+
36
+ /**
37
+ * Show default backgroud image instead of any content.
38
+ */
39
+ defaultBackground: function() {
40
+ var messageContent =
41
+ document
42
+ .querySelector('div[data-content-type=message-content]');
43
+
44
+ messageContent.innerHTML = '';
45
+
46
+ messageContent.style.background =
47
+ "url('" + messageContent.dataset.backgroundImage +
48
+ "') center center no-repeat";
49
+ messageContent.style.backgroundSize = '50%';
50
+ messageContent.style.opacity = '10%';
51
+ },
52
+
53
+ /**
54
+ * Delete all content (message list and message content as well),
55
+ * set default backgroud and the infinite scroll params when we click on
56
+ * the Reload or Delete tabs.
57
+ */
58
+ deleteContent: function() {
59
+ MailGrabber.lastMessageId = -1;
60
+ MailGrabber.page = 1;
61
+ MailGrabber.defaultBackground();
62
+
63
+ document
64
+ .querySelector('ul[data-content-type=message-list]')
65
+ .innerHTML = '';
66
+ },
67
+
68
+ /**
69
+ * Delete a message when we click on the Delete tab. It will remove all
70
+ * content and reload the message list.
71
+ *
72
+ * @param {Number} messageId - which message we would like to delete
73
+ */
74
+ deleteMessage: function(messageId) {
75
+ MailGrabber.request('DELETE', '/message/' + messageId + '.json',
76
+ function() {
77
+ MailGrabber.deleteContent();
78
+ MailGrabber.getMessageList();
79
+ }
80
+ );
81
+ },
82
+
83
+ /**
84
+ * Delete message list when we click on the Clear tab. It will remove
85
+ * everything.
86
+ */
87
+ deleteMessageList: function() {
88
+ MailGrabber.request('DELETE', '/messages.json', function() {
89
+ MailGrabber.deleteContent();
90
+ });
91
+ },
92
+
93
+ /**
94
+ * Get a message and render the message content, when we click on an item
95
+ * from the message list.
96
+ *
97
+ * @param {Number} messageId - which message we would like to see
98
+ */
99
+ getMessage: function(messageId) {
100
+ MailGrabber.request('GET', '/message/' + messageId + '.json',
101
+ function(response) {
102
+ MailGrabber.renderMessageContent(JSON.parse(response));
103
+ }
104
+ );
105
+ },
106
+
107
+ /**
108
+ * Get a list of the messages. Also change the params of the infinite scroll
109
+ * that we can know which page we are on. It checks the message ids to not
110
+ * load those messages which are already on the list.
111
+ */
112
+ getMessageList: function() {
113
+ var messageIds;
114
+
115
+ MailGrabber.request('GET', '/messages.json?page=' + MailGrabber.page +
116
+ '&per_page=' + MailGrabber.perPage,
117
+ function(response) {
118
+ response = JSON.parse(response);
119
+ messageIds = response.map(function(hash) { return hash['id'] });
120
+
121
+ if(response.length > 0) {
122
+ if(messageIds.indexOf(MailGrabber.lastMessageId) === -1) {
123
+ MailGrabber.lastMessageId = messageIds.pop();
124
+ MailGrabber.page++;
125
+ MailGrabber.renderMessageList(response);
126
+ } else {
127
+ MailGrabber.reloadMessageList();
128
+ }
129
+ }
130
+ }
131
+ );
132
+ },
133
+
134
+ /**
135
+ * Scrolling infinitely. Count the height of the list and if we reached the
136
+ * bottom of the list then tries to load more message.
137
+ *
138
+ * @param {Object} messageList - the message list container
139
+ */
140
+ infiniteScroll: function(messageList) {
141
+ var scrollHeight = messageList.scrollHeight;
142
+ var scrollTop = messageList.scrollTop;
143
+ var clientHeight = messageList.clientHeight;
144
+
145
+ if(scrollHeight - scrollTop === clientHeight) {
146
+ MailGrabber.getMessageList();
147
+ }
148
+ },
149
+
150
+ /**
151
+ * Initialize MailGrabber. Add some event listeners to the Reload and the
152
+ * Clear tabs then load messages and the default background.
153
+ */
154
+ init: function() {
155
+ document
156
+ .querySelector('li[data-content-type=message-reload-tab]')
157
+ .addEventListener('click', MailGrabber.reloadMessageList);
158
+
159
+ document
160
+ .querySelector('li[data-content-type=message-clear-tab]')
161
+ .addEventListener('click', MailGrabber.deleteMessageList);
162
+
163
+ MailGrabber.loadMessageList();
164
+ MailGrabber.defaultBackground();
165
+ },
166
+
167
+ /**
168
+ * Format the given date or time.
169
+ *
170
+ * @param {DateTime} dateTime - the message created at attribute
171
+ * @param {String} ouputType - what type we would like to see
172
+ *
173
+ * @return {String} the new format of the date or time
174
+ */
175
+ formatDateTime: function(dateTime, outputType) {
176
+ dateTime = new Date(dateTime);
177
+ var dateTimeNow = new Date();
178
+ // Sun Feb 21 2021 21:00:00 GMT+0100 (Central European Standard Time)
179
+ // 0 1 2 3 4 5 6 7 8 9
180
+ var dateTimeComponents = dateTime.toString().split(' ');
181
+ var output;
182
+
183
+ switch(outputType) {
184
+ case 'messageListDateOrTime':
185
+ if(dateTime.getDate() === dateTimeNow.getDate()) {
186
+ output = MailGrabber.formatTime(dateTimeComponents[4]);
187
+ } else if(dateTime.getFullYear() === dateTimeNow.getFullYear()) {
188
+ output = dateTimeComponents[1] + ' ' + dateTimeComponents[2];
189
+ } else {
190
+ output = dateTimeComponents[3] + ' ' + dateTimeComponents[1] + ' ' +
191
+ dateTimeComponents[2];
192
+ }
193
+
194
+ break;
195
+ default:
196
+ output = dateTimeComponents[3] + ' ' + dateTimeComponents[1] + ' ' +
197
+ dateTimeComponents[2] + ' - ' +
198
+ MailGrabber.formatTime(dateTimeComponents[4]);
199
+ }
200
+
201
+ return output;
202
+ },
203
+
204
+ /**
205
+ * Format the given number (attachment size).
206
+ *
207
+ * @param {Number} size - the size of the attachment in bytes
208
+ *
209
+ * @return {String} the formatted number with unit
210
+ */
211
+ formatSize: function(size) {
212
+ var exponent = (Math.log(size) / Math.log(1024)) | 0;
213
+ var number = +(size / Math.pow(1024, exponent)).toFixed(1);
214
+
215
+ return number + ' ' + ('KMGTPEZY'[exponent - 1] || '') + 'B';
216
+ },
217
+
218
+ /**
219
+ * Format the given time.
220
+ *
221
+ * @param {String} time
222
+ *
223
+ * @return {String} the new format of the time
224
+ */
225
+ formatTime: function(time) {
226
+ var timeComponents = time.split(':');
227
+
228
+ return timeComponents[0] + ':' + timeComponents[1];
229
+ },
230
+
231
+ /**
232
+ * The last message id what loaded. If it is -1 then we have no any
233
+ * messages.
234
+ */
235
+ lastMessageId: -1,
236
+
237
+ /**
238
+ * Load the message list. Also add event listener for infinite scroll.
239
+ */
240
+ loadMessageList: function() {
241
+ var messageList =
242
+ document
243
+ .querySelector('ul[data-content-type=message-list]');
244
+
245
+ messageList.addEventListener('scroll', function() {
246
+ MailGrabber.infiniteScroll(messageList);
247
+ });
248
+
249
+ MailGrabber.getMessageList();
250
+ },
251
+
252
+ /**
253
+ * Params that we can follow how many messages we have on the list. We are
254
+ * loading 15 messages in every requests.
255
+ */
256
+ page: 1,
257
+ perPage: 15,
258
+
259
+ /**
260
+ * Reload the message list. When we have new messages in the database, but
261
+ * we scrolled down or clicked on the Reload tab.
262
+ */
263
+ reloadMessageList: function() {
264
+ MailGrabber.deleteContent();
265
+ MailGrabber.getMessageList();
266
+ },
267
+
268
+ /**
269
+ * Render message attachment. Show the list of attachments at the top of the
270
+ * message content.
271
+ *
272
+ * @param {Object} messageAttachments - the message attachments container
273
+ * @param {Object} messagePart - a message part which we loaded
274
+ */
275
+ renderMessageAttachment: function(messageAttachments, messagePart) {
276
+ var messageAttachment = document.createElement('a');
277
+ var fileSize = document.createElement('span');
278
+ var messageAttachmentTemplate =
279
+ document
280
+ .querySelector(
281
+ 'template[data-content-type=message-attachment-template]'
282
+ )
283
+ .content
284
+ .cloneNode(true);
285
+
286
+ messageAttachment.href =
287
+ 'data:' + messagePart.mime_type + ';base64,' + messagePart.body;
288
+ messageAttachment.download = messagePart.filename;
289
+ messageAttachment.innerHTML = messagePart.filename;
290
+ messageAttachment.classList.add('color-black', 'no-text-decoration');
291
+
292
+ fileSize.innerHTML = MailGrabber.formatSize(messagePart.size);
293
+ fileSize.classList.add('color-gray', 'font-size-0_9', 'padding-left-10');
294
+
295
+ [messageAttachment, fileSize].forEach(function(node) {
296
+ messageAttachmentTemplate
297
+ .querySelector('li[data-content-type=message-attachment]')
298
+ .appendChild(node);
299
+ });
300
+
301
+ messageAttachments.classList.remove('hide');
302
+ messageAttachments.appendChild(messageAttachmentTemplate);
303
+ },
304
+
305
+ /**
306
+ * Render the HTML part of the message. If the message has inline images
307
+ * then it will render those images as well. An iframe will contain this
308
+ * content.
309
+ *
310
+ * @param {Object} iFrame - the iframe HTML tag
311
+ * @param {Object} messageParts - the parts of the message
312
+ * @param {Object} messageHtmlPart - the HTML part of the message
313
+ */
314
+ renderMessageHtmlPart: function(iFrame, messageParts, messageHtmlPart) {
315
+ var messageInlineAttachmentRegExp = new RegExp("cid:");
316
+
317
+ if(messageInlineAttachmentRegExp.test(messageHtmlPart)) {
318
+ messageHtmlPart =
319
+ MailGrabber.renderMessageInlineAttachments(
320
+ messageParts, messageHtmlPart
321
+ );
322
+ }
323
+
324
+ iFrame.srcdoc = messageHtmlPart;
325
+ iFrame.onload = function() {
326
+ iFrame.height = iFrame.contentDocument.body.scrollHeight + 65;
327
+ }
328
+ },
329
+
330
+ /**
331
+ * Render inline images of the message. Change the cid:something12345 with
332
+ * the encoded image content.
333
+ *
334
+ * @param {Object} messageParts - the parts of the message
335
+ * @param {Object} messageHtmlPart - the HTML part of the message
336
+ *
337
+ * @return {Object} messageHtmlPart - the modified HTML part of the message
338
+ */
339
+ renderMessageInlineAttachments: function(messageParts, messageHtmlPart) {
340
+ messageParts.forEach(function(messagePart) {
341
+ if(messagePart.is_attachment === 1 && messagePart.is_inline === 1) {
342
+ messageHtmlPart = messageHtmlPart.replace('cid:' + messagePart.cid,
343
+ 'data:' + messagePart.mime_type + ';base64,' + messagePart.body);
344
+ }
345
+ });
346
+
347
+ return messageHtmlPart;
348
+ },
349
+
350
+ /**
351
+ * Render the content of the message (all parts, inline attachments and
352
+ * attachments). Also it sets up event listeners of the HTML, PlainText,
353
+ * Raw, Delete and Close tabs.
354
+ *
355
+ * @param {Object} response - the response the get message request
356
+ */
357
+ renderMessageContent: function(response) {
358
+ var message = response.message;
359
+ var messageParts = response.message_parts;
360
+ var messageContentTemplate =
361
+ document
362
+ .querySelector('template[data-content-type=message-content-template]')
363
+ .content
364
+ .cloneNode(true);
365
+
366
+ var messageContent =
367
+ document
368
+ .querySelector('div[data-content-type=message-content]');
369
+
370
+ messageContent.removeAttribute('style');
371
+ messageContent.innerHTML = '';
372
+
373
+ messageContentTemplate
374
+ .querySelector('div[data-content-type=message-subject]')
375
+ .innerHTML = message.subject;
376
+
377
+ messageContentTemplate
378
+ .querySelector('dl[data-content-type=metadata]')
379
+ .innerHTML = MailGrabber.renderMetadata(message);
380
+
381
+ messageContentTemplate
382
+ .querySelector('time[data-content-type=message-sent-at]')
383
+ .innerHTML = MailGrabber.formatDateTime(message.created_at);
384
+
385
+ messageContentTemplate
386
+ .querySelectorAll('[data-message-tab]')
387
+ .forEach(function(tab) {
388
+ tab.addEventListener('click', MailGrabber.changeMessageContent);
389
+ });
390
+
391
+ messageContentTemplate
392
+ .querySelector('li[data-content-type=message-delete-tab]')
393
+ .addEventListener('click', function() {
394
+ MailGrabber.deleteMessage(message.id);
395
+ });
396
+
397
+ messageContentTemplate
398
+ .querySelector('li[data-content-type=message-close-tab]')
399
+ .addEventListener('click', MailGrabber.defaultBackground);
400
+
401
+ messageParts.forEach(function(messagePart) {
402
+ if(messagePart.is_attachment === 0 && messagePart.is_inline === 0) {
403
+ switch(messagePart.mime_type) {
404
+ case 'text/html':
405
+ MailGrabber.renderMessageHtmlPart(
406
+ messageContentTemplate
407
+ .querySelector('iframe[data-content-type=message-html-body]'),
408
+ messageParts,
409
+ messagePart.body
410
+ );
411
+
412
+ break;
413
+ case 'text/plain':
414
+ messageContentTemplate
415
+ .querySelector('pre[data-content-type=message-text-body]')
416
+ .innerText = messagePart.body;
417
+
418
+ break;
419
+ }
420
+ } else if(messagePart.is_attachment === 1 &&
421
+ messagePart.is_inline === 0) {
422
+ MailGrabber.renderMessageAttachment(
423
+ messageContentTemplate
424
+ .querySelector('ul[data-content-type=message-attachments]'),
425
+ messagePart
426
+ );
427
+ }
428
+ });
429
+
430
+ messageContentTemplate
431
+ .querySelector('pre[data-content-type=message-raw-body]')
432
+ .innerText = message.raw;
433
+
434
+ messageContent.appendChild(messageContentTemplate);
435
+ },
436
+
437
+ /**
438
+ * Render the list of the messages. Also add event listener when click on a
439
+ * message then it will load that conent.
440
+ *
441
+ * @param {Object} messages - the list of the given message.
442
+ */
443
+ renderMessageList: function(messages) {
444
+ var messageListTemplate;
445
+
446
+ var messageList =
447
+ document
448
+ .querySelector('ul[data-content-type=message-list]');
449
+
450
+ messages.forEach(function(message) {
451
+ messageListTemplate =
452
+ document
453
+ .querySelector('template[data-content-type=message-list-template]')
454
+ .content
455
+ .cloneNode(true);
456
+
457
+ messageListTemplate
458
+ .querySelector('li')
459
+ .addEventListener('click', function() {
460
+ MailGrabber.getMessage(message.id);
461
+ });
462
+
463
+ messageListTemplate
464
+ .querySelector('div[data-content-type=message-senders]')
465
+ .innerHTML = message.senders;
466
+
467
+ messageListTemplate
468
+ .querySelector('time[data-content-type=message-sent-at]')
469
+ .innerHTML =
470
+ MailGrabber
471
+ .formatDateTime(message.created_at, 'messageListDateOrTime');
472
+
473
+ messageListTemplate
474
+ .querySelector('div[data-content-type=message-subject]')
475
+ .innerHTML = message.subject;
476
+
477
+ messageList.appendChild(messageListTemplate);
478
+ });
479
+ },
480
+
481
+ /**
482
+ * Render senders and recipients data of the message.
483
+ *
484
+ * @param {Object} message - the requested message
485
+ *
486
+ * @return {Object} the rendered metadata
487
+ */
488
+ renderMetadata: function(message) {
489
+ var metadata =
490
+ '<dt>From:</dt><dd>' + message.senders + '</dd>' +
491
+ '<dt>To:</dt><dd>' + message.recipients + '</dd>';
492
+
493
+ if(message.carbon_copy) {
494
+ metadata += '<dt>Cc:</dt><dd>' + message.carbon_copy + '</dd>';
495
+ }
496
+
497
+ if(message.blind_carbon_copy) {
498
+ metadata += '<dt>Bcc:</dt><dd>' + message.blind_carbon_copy + '</dd>';
499
+ }
500
+
501
+ return metadata;
502
+ },
503
+
504
+ /**
505
+ * Request function to get data from the server.
506
+ *
507
+ * @param {String} method - the request method e.g. GET, POST, DELETE
508
+ * @param {String} path - the path which we can get/send data
509
+ * @param {Function} fn - the function which handle the response
510
+ */
511
+ request: function(method, path, fn) {
512
+ var xhr = new XMLHttpRequest();
513
+
514
+ xhr.onload = function() {
515
+ if(xhr.status === 200) {
516
+ fn(xhr.responseText);
517
+ } else {
518
+ console.log('MailGrabberRequestError:', xhr.status, xhr.statusText);
519
+ }
520
+ };
521
+ xhr.open(method, MailGrabber.rootPath() + path, true);
522
+ xhr.send();
523
+ },
524
+
525
+ /**
526
+ * Root path which returns back with the server's root path. It can be empty
527
+ * string or a string. It depends on how the server is running (standalone
528
+ * or in Ruby on Rails).
529
+ */
530
+ rootPath: function() {
531
+ return document.querySelector('body').dataset.rootPath;
532
+ }
533
+ };
534
+
535
+ /**
536
+ * When DOM loaded then call MailGrabber's init function.
537
+ */
538
+ document.addEventListener('DOMContentLoaded', MailGrabber.init);
539
+ }).call(this);