mail_grabber 1.0.0.rc1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: