mail_grabber 1.0.0.rc1 → 1.0.0

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
  SHA256:
3
- metadata.gz: d564e5c8027b8dd25676e1076cddefda9c055cf694df0fb8824ef836c0c8c31d
4
- data.tar.gz: 4599ee2a8e4491b26df2d44005eeb11594993b889bdc3a1e277c284b6a8422bf
3
+ metadata.gz: 700d9bdbeeed0c02117ec588e990fb4d69e5b239aa4fec3d13fbc70acbba1230
4
+ data.tar.gz: 71b84af90f8496cb0a07d9b96312ec37efa3b03e5fc871d57bd11468affabfb0
5
5
  SHA512:
6
- metadata.gz: 5e58191d8045ef116faffeb4574f5d875e0cf0c9a1387354d151226981d318752bc9ba675e0d8ade11629f45f69ac247f65d6bc71724f4655b00612d199c52e9
7
- data.tar.gz: 3b07b4809a2d9326ff95790f02c0d2ef89252f688e9d7968784aae2d37a69bffc431c74a5495f187faafe1f5b5d3538d29f476e0cda58b95bcaf816d39b4a693
6
+ metadata.gz: 6aca1623fb80aa3f79ef16050d799c955352ac463cdd8dd03928b828ed5abb6a4821f19f7045ab592e79ad1524e3cd04ff59d4df2c7055064969e1ac00e9edb3
7
+ data.tar.gz: 981f1b1bb7f4310e3b6c703ea75e5c43a7e8626a377a80884a660c4d3f69b6d3546b21fa9acbcfea1c657379caea4aa6ed9ca4e508a7d374878efff255dadc5a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Change log
2
2
 
3
+ ## 1.0.0 (2021-04-02)
4
+
5
+ ### Changes
6
+
7
+ * Update documentation.
8
+ * Change javascript to hide HTML tab if mail does not have HTML part.
9
+ * Refactoring the JavaScript code.
10
+ * Change the documentation uri in the gemspec file.
11
+ * Update .rubocop.yml.
12
+ * Update gems.
13
+
14
+ ### Bug fixes
15
+
16
+ * Fix 3x load message list when reload tab and infinite scroll was used.
17
+
18
+
3
19
  ## 1.0.0.rc1 (2021-03-20)
4
20
 
5
21
  * Implement MailGrabber methods and functionality. See [README.md](https://github.com/MailToolbox/mail_grabber/blob/main/README.md)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MailGrabber
4
- VERSION = '1.0.0.rc1'
4
+ VERSION = '1.0.0'
5
5
  end
@@ -1,539 +1,148 @@
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]);
1
+ var MailGrabberApplication = {
2
+ /**
3
+ * Delete a message when we click on the Delete tab. It will remove all
4
+ * content and reload the message list.
5
+ *
6
+ * @param {Number} messageId - which message we would like to delete
7
+ */
8
+ deleteMessage: function(messageId) {
9
+ MailGrabberApplication.request('DELETE', '/message/' + messageId + '.json',
10
+ function() {
11
+ MailGrabberDOM.deleteContent();
12
+ MailGrabberApplication.getMessageList();
199
13
  }
14
+ );
15
+ },
200
16
 
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
- }
17
+ /**
18
+ * Delete message list when we click on the Clear tab. It will remove
19
+ * everything.
20
+ */
21
+ deleteMessageList: function() {
22
+ MailGrabberApplication.request('DELETE', '/messages.json', function() {
23
+ MailGrabberDOM.deleteContent();
24
+ });
25
+ },
323
26
 
324
- iFrame.srcdoc = messageHtmlPart;
325
- iFrame.onload = function() {
326
- iFrame.height = iFrame.contentDocument.body.scrollHeight + 65;
27
+ /**
28
+ * Get a message and render the message content, when we click on an item
29
+ * from the message list.
30
+ *
31
+ * @param {Number} messageId - which message we would like to see
32
+ */
33
+ getMessage: function(messageId) {
34
+ MailGrabberApplication.request('GET', '/message/' + messageId + '.json',
35
+ function(response) {
36
+ MailGrabberMessageContent.render(JSON.parse(response));
327
37
  }
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);
38
+ );
39
+ },
365
40
 
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;
41
+ /**
42
+ * Get a list of the messages. Also change the params of the infinite scroll
43
+ * that we can know which page we are on. It checks the message ids to not
44
+ * load those messages which are already on the list.
45
+ */
46
+ getMessageList: function() {
47
+ var messageIds;
48
+
49
+ MailGrabberApplication.request('GET', '/messages.json?page=' +
50
+ MailGrabberVariables.page + '&per_page=' + MailGrabberVariables.perPage,
51
+ function(response) {
52
+ response = JSON.parse(response);
53
+ messageIds = response.map(function(hash) { return hash['id'] });
54
+
55
+ if(response.length > 0) {
56
+ if(messageIds.indexOf(MailGrabberVariables.lastMessageId) === -1) {
57
+ MailGrabberVariables.lastMessageId = messageIds.pop();
58
+ MailGrabberVariables.messageListReloading = false;
59
+ MailGrabberVariables.page++;
60
+ MailGrabberMessageList.render(response);
61
+ } else {
62
+ MailGrabberApplication.reloadMessageList();
419
63
  }
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
64
  }
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;
65
+ }
66
+ );
67
+ },
476
68
 
477
- messageList.appendChild(messageListTemplate);
478
- });
479
- },
69
+ /**
70
+ * Scrolling infinitely. Count the height of the list and if we reached the
71
+ * bottom of the list then tries to load more message.
72
+ *
73
+ * @param {Object} messageList - the message list container
74
+ */
75
+ infiniteScroll: function(messageList) {
76
+ var scrollHeight = messageList.scrollHeight;
77
+ var scrollTop = messageList.scrollTop;
78
+ var clientHeight = messageList.clientHeight;
79
+
80
+ if(scrollHeight - scrollTop === clientHeight &&
81
+ !MailGrabberVariables.messageListReloading) {
82
+ MailGrabberApplication.getMessageList();
83
+ }
84
+ },
480
85
 
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>';
86
+ /**
87
+ * Initialize MailGrabber. Add some event listeners to the Reload and the
88
+ * Clear tabs then load messages and the default background.
89
+ */
90
+ init: function() {
91
+ document
92
+ .querySelector('li[data-content-type=message-reload-tab]')
93
+ .addEventListener('click', MailGrabberApplication.reloadMessageList);
492
94
 
493
- if(message.carbon_copy) {
494
- metadata += '<dt>Cc:</dt><dd>' + message.carbon_copy + '</dd>';
495
- }
95
+ document
96
+ .querySelector('li[data-content-type=message-clear-tab]')
97
+ .addEventListener('click', MailGrabberApplication.deleteMessageList);
496
98
 
497
- if(message.blind_carbon_copy) {
498
- metadata += '<dt>Bcc:</dt><dd>' + message.blind_carbon_copy + '</dd>';
499
- }
99
+ MailGrabberApplication.loadMessageList();
100
+ MailGrabberDOM.defaultBackground();
101
+ },
500
102
 
501
- return metadata;
502
- },
103
+ /**
104
+ * Load the message list. Also add event listener for infinite scroll.
105
+ */
106
+ loadMessageList: function() {
107
+ var messageList =
108
+ document
109
+ .querySelector('ul[data-content-type=message-list]');
503
110
 
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();
111
+ messageList.addEventListener('scroll', function() {
112
+ MailGrabberApplication.infiniteScroll(messageList);
113
+ });
513
114
 
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
- },
115
+ MailGrabberApplication.getMessageList();
116
+ },
524
117
 
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
- };
118
+ /**
119
+ * Reload the message list. When we have new messages in the database, but
120
+ * we scrolled down or clicked on the Reload tab.
121
+ */
122
+ reloadMessageList: function() {
123
+ MailGrabberVariables.messageListReloading = true;
124
+ MailGrabberDOM.deleteContent();
125
+ MailGrabberApplication.getMessageList();
126
+ },
534
127
 
535
128
  /**
536
- * When DOM loaded then call MailGrabber's init function.
129
+ * Request function to get data from the server.
130
+ *
131
+ * @param {String} method - the request method e.g. GET, POST, DELETE
132
+ * @param {String} path - the path which we can get/send data
133
+ * @param {Function} fn - the function which handle the response
537
134
  */
538
- document.addEventListener('DOMContentLoaded', MailGrabber.init);
539
- }).call(this);
135
+ request: function(method, path, fn) {
136
+ var xhr = new XMLHttpRequest();
137
+
138
+ xhr.onload = function() {
139
+ if(xhr.status === 200) {
140
+ fn(xhr.responseText);
141
+ } else {
142
+ console.log('MailGrabberRequestError:', xhr.status, xhr.statusText);
143
+ }
144
+ };
145
+ xhr.open(method, MailGrabberDOM.rootPath() + path, true);
146
+ xhr.send();
147
+ }
148
+ };
@@ -0,0 +1,86 @@
1
+ var MailGrabberDOM = {
2
+ /**
3
+ * Change which content (message part) should show. When the page is loading
4
+ * the HTML content will be active and the others will be hidden. When we
5
+ * click on tab e.g. Plain Text then this content will active and other
6
+ * hidden.
7
+ *
8
+ * @param {Object} event - which part we clicked
9
+ */
10
+ changeMessageContent: function(event) {
11
+ var messageTabs =
12
+ document
13
+ .querySelectorAll('[data-message-tab]');
14
+
15
+ var messageContents =
16
+ document
17
+ .querySelectorAll('[data-message-content]');
18
+
19
+ var clickedTabType = event.target.dataset.messageTab;
20
+
21
+ messageTabs.forEach(function(messageTab, index) {
22
+ messageTab.classList.remove('active');
23
+ messageContents[index].classList.remove('hide');
24
+
25
+ if(messageTab.dataset.messageTab === clickedTabType) {
26
+ messageTab.classList.add('active');
27
+ }
28
+
29
+ if(messageContents[index].dataset.messageContent !== clickedTabType) {
30
+ messageContents[index].classList.add('hide');
31
+ }
32
+ });
33
+ },
34
+
35
+ /**
36
+ * Create a clone from an element e.g. template tag.
37
+ *
38
+ * @param {String} selector - which describe how find the element
39
+ *
40
+ * @return {Object} the clone of the found element
41
+ */
42
+ cloneContent: function(selector) {
43
+ return document.querySelector(selector).content.cloneNode(true);
44
+ },
45
+
46
+ /**
47
+ * Show default backgroud image instead of any content.
48
+ */
49
+ defaultBackground: function() {
50
+ var messageContent =
51
+ document
52
+ .querySelector('div[data-content-type=message-content]');
53
+
54
+ messageContent.innerHTML = '';
55
+
56
+ messageContent.style.background =
57
+ "url('" + messageContent.dataset.backgroundImage +
58
+ "') center center no-repeat";
59
+ messageContent.style.backgroundSize = '50%';
60
+ messageContent.style.opacity = '10%';
61
+ },
62
+
63
+ /**
64
+ * Delete all content (message list and message content as well),
65
+ * set default backgroud and the infinite scroll params when we click on
66
+ * the Reload or Delete tabs.
67
+ */
68
+ deleteContent: function() {
69
+ MailGrabberVariables.lastMessageId = -1;
70
+ MailGrabberVariables.page = 1;
71
+ MailGrabberDOM.defaultBackground();
72
+
73
+ document
74
+ .querySelector('ul[data-content-type=message-list]')
75
+ .innerHTML = '';
76
+ },
77
+
78
+ /**
79
+ * Root path which returns back with the server's root path. It can be empty
80
+ * string or a string. It depends on how the server is running (standalone
81
+ * or in Ruby on Rails).
82
+ */
83
+ rootPath: function() {
84
+ return document.querySelector('body').dataset.rootPath;
85
+ }
86
+ };
@@ -0,0 +1,36 @@
1
+ var MailGrabberMessageAttachment = {
2
+ /**
3
+ * Render message attachment. Show the list of attachments at the top of the
4
+ * message content.
5
+ *
6
+ * @param {Object} messageAttachments - the message attachments container
7
+ * @param {Object} messagePart - a message part which we loaded
8
+ */
9
+ render: function(messageAttachments, messagePart) {
10
+ var messageAttachment = document.createElement('a');
11
+ var fileSize = document.createElement('span');
12
+ var messageAttachmentTemplate =
13
+ MailGrabberDOM
14
+ .cloneContent(
15
+ 'template[data-content-type=message-attachment-template]'
16
+ );
17
+
18
+ messageAttachment.href =
19
+ 'data:' + messagePart.mime_type + ';base64,' + messagePart.body;
20
+ messageAttachment.download = messagePart.filename;
21
+ messageAttachment.innerHTML = messagePart.filename;
22
+ messageAttachment.classList.add('color-black', 'no-text-decoration');
23
+
24
+ fileSize.innerHTML = MailGrabberUtilities.formatSize(messagePart.size);
25
+ fileSize.classList.add('color-gray', 'font-size-0_9', 'padding-left-10');
26
+
27
+ [messageAttachment, fileSize].forEach(function(node) {
28
+ messageAttachmentTemplate
29
+ .querySelector('li[data-content-type=message-attachment]')
30
+ .appendChild(node);
31
+ });
32
+
33
+ messageAttachments.classList.remove('hide');
34
+ messageAttachments.appendChild(messageAttachmentTemplate);
35
+ }
36
+ };
@@ -0,0 +1,114 @@
1
+ var MailGrabberMessageContent = {
2
+ /**
3
+ * Fill up the message content template with content.
4
+ *
5
+ * @param {Object} response - from the server with data
6
+ *
7
+ * @return {Object} the filled up template
8
+ */
9
+ fillUpTemplateWith: function(response) {
10
+ var message = response.message;
11
+ var messageParts = response.message_parts;
12
+ var messageContentTemplate =
13
+ MailGrabberDOM
14
+ .cloneContent('template[data-content-type=message-content-template]');
15
+
16
+ messageContentTemplate
17
+ .querySelector('div[data-content-type=message-subject]')
18
+ .innerHTML = message.subject;
19
+
20
+ MailGrabberMessageMetadata.render(
21
+ messageContentTemplate
22
+ .querySelector('dl[data-content-type=metadata]'),
23
+ message
24
+ );
25
+
26
+ messageContentTemplate
27
+ .querySelector('time[data-content-type=message-sent-at]')
28
+ .innerHTML = MailGrabberUtilities.formatDateTime(message.created_at);
29
+
30
+ messageContentTemplate
31
+ .querySelectorAll('[data-message-tab]')
32
+ .forEach(function(tab) {
33
+ tab.addEventListener('click', MailGrabberDOM.changeMessageContent);
34
+ });
35
+
36
+ messageContentTemplate
37
+ .querySelector('li[data-content-type=message-delete-tab]')
38
+ .addEventListener('click', function() {
39
+ MailGrabberApplication.deleteMessage(message.id);
40
+ });
41
+
42
+ messageContentTemplate
43
+ .querySelector('li[data-content-type=message-close-tab]')
44
+ .addEventListener('click', MailGrabberDOM.defaultBackground);
45
+
46
+ messageParts.forEach(function(messagePart) {
47
+ if(messagePart.is_attachment === 0 && messagePart.is_inline === 0) {
48
+ switch(messagePart.mime_type) {
49
+ case 'text/html':
50
+ MailGrabberVariables.messageHasHtmlPart = true;
51
+ MailGrabberMessageHtmlPart.render(
52
+ messageContentTemplate
53
+ .querySelector('iframe[data-content-type=message-html-body]'),
54
+ messageParts,
55
+ messagePart.body
56
+ );
57
+
58
+ break;
59
+ case 'text/plain':
60
+ messageContentTemplate
61
+ .querySelector('pre[data-content-type=message-text-body]')
62
+ .innerText = messagePart.body;
63
+
64
+ break;
65
+ }
66
+ } else if(messagePart.is_attachment === 1 &&
67
+ messagePart.is_inline === 0) {
68
+ MailGrabberMessageAttachment.render(
69
+ messageContentTemplate
70
+ .querySelector('ul[data-content-type=message-attachments]'),
71
+ messagePart
72
+ );
73
+ }
74
+ });
75
+
76
+ messageContentTemplate
77
+ .querySelector('pre[data-content-type=message-raw-body]')
78
+ .innerText = message.raw;
79
+
80
+ return messageContentTemplate;
81
+ },
82
+
83
+ /**
84
+ * Render the content of the message (all parts, inline attachments and
85
+ * attachments). Also it sets up event listeners of the HTML, PlainText,
86
+ * Raw, Delete and Close tabs.
87
+ *
88
+ * @param {Object} response - the response of the get message request
89
+ */
90
+ render: function(response) {
91
+ var messageContent =
92
+ document
93
+ .querySelector('div[data-content-type=message-content]');
94
+
95
+ messageContent.removeAttribute('style');
96
+ messageContent.innerHTML = '';
97
+
98
+ MailGrabberVariables.messageHasHtmlPart = false;
99
+
100
+ messageContent.appendChild(
101
+ MailGrabberMessageContent.fillUpTemplateWith(response)
102
+ );
103
+
104
+ if(!MailGrabberVariables.messageHasHtmlPart) {
105
+ messageContent
106
+ .querySelector('li[data-message-tab=text]')
107
+ .click();
108
+
109
+ messageContent
110
+ .querySelector('li[data-message-tab=html]')
111
+ .classList.add('hide');
112
+ }
113
+ }
114
+ };
@@ -0,0 +1,26 @@
1
+ var MailGrabberMessageHtmlPart = {
2
+ /**
3
+ * Render the HTML part of the message. If the message has inline images
4
+ * then it will render those images as well. An iframe will contain this
5
+ * content.
6
+ *
7
+ * @param {Object} iFrame - the iframe HTML tag
8
+ * @param {Object} messageParts - the parts of the message
9
+ * @param {Object} messageHtmlPart - the HTML part of the message
10
+ */
11
+ render: function(iFrame, messageParts, messageHtmlPart) {
12
+ var messageInlineAttachmentRegExp = new RegExp('cid:');
13
+
14
+ if(messageInlineAttachmentRegExp.test(messageHtmlPart)) {
15
+ messageHtmlPart =
16
+ MailGrabberMessageInlineAttachments.render(
17
+ messageParts, messageHtmlPart
18
+ );
19
+ }
20
+
21
+ iFrame.srcdoc = messageHtmlPart;
22
+ iFrame.onload = function() {
23
+ iFrame.height = iFrame.contentDocument.body.scrollHeight + 65;
24
+ }
25
+ }
26
+ };
@@ -0,0 +1,21 @@
1
+ var MailGrabberMessageInlineAttachments = {
2
+ /**
3
+ * Render inline images of the message. Change the cid:something12345 with
4
+ * the encoded image content.
5
+ *
6
+ * @param {Object} messageParts - the parts of the message
7
+ * @param {Object} messageHtmlPart - the HTML part of the message
8
+ *
9
+ * @return {Object} messageHtmlPart - the modified HTML part of the message
10
+ */
11
+ render: function(messageParts, messageHtmlPart) {
12
+ messageParts.forEach(function(messagePart) {
13
+ if(messagePart.is_attachment === 1 && messagePart.is_inline === 1) {
14
+ messageHtmlPart = messageHtmlPart.replace('cid:' + messagePart.cid,
15
+ 'data:' + messagePart.mime_type + ';base64,' + messagePart.body);
16
+ }
17
+ });
18
+
19
+ return messageHtmlPart;
20
+ }
21
+ };
@@ -0,0 +1,54 @@
1
+ var MailGrabberMessageList = {
2
+ /**
3
+ * Fill up the message list template with content.
4
+ *
5
+ * @param {Object} message
6
+ *
7
+ * @return {Object} the filled up template
8
+ */
9
+ fillUpTemplateWith: function(message) {
10
+ var messageListTemplate =
11
+ MailGrabberDOM
12
+ .cloneContent('template[data-content-type=message-list-template]');
13
+
14
+ messageListTemplate
15
+ .querySelector('li')
16
+ .addEventListener('click', function() {
17
+ MailGrabberApplication.getMessage(message.id);
18
+ });
19
+
20
+ messageListTemplate
21
+ .querySelector('div[data-content-type=message-senders]')
22
+ .innerHTML = message.senders;
23
+
24
+ messageListTemplate
25
+ .querySelector('time[data-content-type=message-sent-at]')
26
+ .innerHTML =
27
+ MailGrabberUtilities
28
+ .formatDateTime(message.created_at, 'messageListDateOrTime');
29
+
30
+ messageListTemplate
31
+ .querySelector('div[data-content-type=message-subject]')
32
+ .innerHTML = message.subject;
33
+
34
+ return messageListTemplate;
35
+ },
36
+
37
+ /**
38
+ * Render the list of the messages. Also add event listener when click on a
39
+ * message then it will load that conent.
40
+ *
41
+ * @param {Object} messages - the list of the given message.
42
+ */
43
+ render: function(messages) {
44
+ var messageList =
45
+ document
46
+ .querySelector('ul[data-content-type=message-list]');
47
+
48
+ messages.forEach(function(message) {
49
+ messageList.appendChild(
50
+ MailGrabberMessageList.fillUpTemplateWith(message)
51
+ );
52
+ });
53
+ }
54
+ };
@@ -0,0 +1,23 @@
1
+ var MailGrabberMessageMetadata = {
2
+ /**
3
+ * Render senders and recipients data of the message.
4
+ *
5
+ * @param {Object} messageMetadata - the metadata container
6
+ * @param {Object} message - the requested message
7
+ */
8
+ render: function(messageMetadata, message) {
9
+ var metadata =
10
+ '<dt>From:</dt><dd>' + message.senders + '</dd>' +
11
+ '<dt>To:</dt><dd>' + message.recipients + '</dd>';
12
+
13
+ if(message.carbon_copy) {
14
+ metadata += '<dt>Cc:</dt><dd>' + message.carbon_copy + '</dd>';
15
+ }
16
+
17
+ if(message.blind_carbon_copy) {
18
+ metadata += '<dt>Bcc:</dt><dd>' + message.blind_carbon_copy + '</dd>';
19
+ }
20
+
21
+ messageMetadata.innerHTML = metadata;
22
+ }
23
+ };
@@ -0,0 +1,65 @@
1
+ var MailGrabberUtilities = {
2
+ /**
3
+ * Format the given date or time.
4
+ *
5
+ * @param {DateTime} dateTime - the message created at attribute
6
+ * @param {String} ouputType - what type we would like to see
7
+ *
8
+ * @return {String} the new format of the date or time
9
+ */
10
+ formatDateTime: function(dateTime, outputType) {
11
+ dateTime = new Date(dateTime);
12
+ var dateTimeNow = new Date();
13
+ // Sun Feb 21 2021 21:00:00 GMT+0100 (Central European Standard Time)
14
+ // 0 1 2 3 4 5 6 7 8 9
15
+ var dateTimeComponents = dateTime.toString().split(' ');
16
+ var output;
17
+
18
+ switch(outputType) {
19
+ case 'messageListDateOrTime':
20
+ if(dateTime.getDate() === dateTimeNow.getDate()) {
21
+ output = MailGrabberUtilities.formatTime(dateTimeComponents[4]);
22
+ } else if(dateTime.getFullYear() === dateTimeNow.getFullYear()) {
23
+ output = dateTimeComponents[1] + ' ' + dateTimeComponents[2];
24
+ } else {
25
+ output = dateTimeComponents[3] + ' ' + dateTimeComponents[1] + ' ' +
26
+ dateTimeComponents[2];
27
+ }
28
+
29
+ break;
30
+ default:
31
+ output = dateTimeComponents[3] + ' ' + dateTimeComponents[1] + ' ' +
32
+ dateTimeComponents[2] + ' - ' +
33
+ MailGrabberUtilities.formatTime(dateTimeComponents[4]);
34
+ }
35
+
36
+ return output;
37
+ },
38
+
39
+ /**
40
+ * Format the given number (attachment size).
41
+ *
42
+ * @param {Number} size - the size of the attachment in bytes
43
+ *
44
+ * @return {String} the formatted number with unit
45
+ */
46
+ formatSize: function(size) {
47
+ var exponent = (Math.log(size) / Math.log(1024)) | 0;
48
+ var number = +(size / Math.pow(1024, exponent)).toFixed(1);
49
+
50
+ return number + ' ' + ('KMGTPEZY'[exponent - 1] || '') + 'B';
51
+ },
52
+
53
+ /**
54
+ * Format the given time.
55
+ *
56
+ * @param {String} time
57
+ *
58
+ * @return {String} the new format of the time
59
+ */
60
+ formatTime: function(time) {
61
+ var timeComponents = time.split(':');
62
+
63
+ return timeComponents[0] + ':' + timeComponents[1];
64
+ }
65
+ };
@@ -0,0 +1,24 @@
1
+ var MailGrabberVariables = {
2
+ /**
3
+ * The last message id what loaded. If it is -1 then we have no any
4
+ * messages.
5
+ */
6
+ lastMessageId: -1,
7
+
8
+ /**
9
+ * The message has HTML part or not.
10
+ */
11
+ messageHasHtmlPart: false,
12
+
13
+ /**
14
+ * The message is list reloading or not (click on the Reload tab).
15
+ */
16
+ messageListReloading: false,
17
+
18
+ /**
19
+ * Params that we can follow how many messages we have on the list. We are
20
+ * loading 15 messages in every requests.
21
+ */
22
+ page: 1,
23
+ perPage: 15
24
+ };
@@ -0,0 +1,6 @@
1
+ (function() {
2
+ /**
3
+ * When DOM loaded then call MailGrabber's init function.
4
+ */
5
+ document.addEventListener('DOMContentLoaded', MailGrabberApplication.init);
6
+ })();
@@ -11,6 +11,16 @@
11
11
  <link rel="stylesheet" href="<%= root_path %>/stylesheets/application.css" type="text/css" charset="utf-8">
12
12
 
13
13
  <script src="<%= root_path %>/javascripts/application.js"></script>
14
+ <script src="<%= root_path %>/javascripts/dom.js"></script>
15
+ <script src="<%= root_path %>/javascripts/message_attachment.js"></script>
16
+ <script src="<%= root_path %>/javascripts/message_content.js"></script>
17
+ <script src="<%= root_path %>/javascripts/message_html_part.js"></script>
18
+ <script src="<%= root_path %>/javascripts/message_inline_attachments.js"></script>
19
+ <script src="<%= root_path %>/javascripts/message_list.js"></script>
20
+ <script src="<%= root_path %>/javascripts/message_metadata.js"></script>
21
+ <script src="<%= root_path %>/javascripts/utilities.js"></script>
22
+ <script src="<%= root_path %>/javascripts/variables.js"></script>
23
+ <script src="<%= root_path %>/javascripts/web.js"></script>
14
24
  </head>
15
25
 
16
26
  <body data-root-path="<%= root_path %>">
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mail_grabber
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Norbert Szivós
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-20 00:00:00.000000000 Z
11
+ date: 2021-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mail
@@ -78,6 +78,16 @@ files:
78
78
  - lib/mail_grabber/web/application_router.rb
79
79
  - lib/mail_grabber/web/assets/images/mail_grabber515x500.png
80
80
  - lib/mail_grabber/web/assets/javascripts/application.js
81
+ - lib/mail_grabber/web/assets/javascripts/dom.js
82
+ - lib/mail_grabber/web/assets/javascripts/message_attachment.js
83
+ - lib/mail_grabber/web/assets/javascripts/message_content.js
84
+ - lib/mail_grabber/web/assets/javascripts/message_html_part.js
85
+ - lib/mail_grabber/web/assets/javascripts/message_inline_attachments.js
86
+ - lib/mail_grabber/web/assets/javascripts/message_list.js
87
+ - lib/mail_grabber/web/assets/javascripts/message_metadata.js
88
+ - lib/mail_grabber/web/assets/javascripts/utilities.js
89
+ - lib/mail_grabber/web/assets/javascripts/variables.js
90
+ - lib/mail_grabber/web/assets/javascripts/web.js
81
91
  - lib/mail_grabber/web/assets/stylesheets/application.css
82
92
  - lib/mail_grabber/web/views/_message_attachment_template.html.erb
83
93
  - lib/mail_grabber/web/views/_message_content_template.html.erb
@@ -91,7 +101,7 @@ metadata:
91
101
  source_code_uri: https://github.com/MailToolbox/mail_grabber
92
102
  changelog_uri: https://github.com/MailToolbox/mail_grabber/blob/main/CHANGELOG.md
93
103
  bug_tracker_uri: https://github.com/MailToolbox/mail_grabber/issues
94
- documentation_uri: https://rubydoc.info/gems/mail_grabber
104
+ documentation_uri: https://rubydoc.info/github/MailToolbox/mail_grabber/main
95
105
  post_install_message:
96
106
  rdoc_options: []
97
107
  require_paths:
@@ -103,9 +113,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
113
  version: 2.5.0
104
114
  required_rubygems_version: !ruby/object:Gem::Requirement
105
115
  requirements:
106
- - - ">"
116
+ - - ">="
107
117
  - !ruby/object:Gem::Version
108
- version: 1.3.1
118
+ version: '0'
109
119
  requirements: []
110
120
  rubygems_version: 3.1.4
111
121
  signing_key: