-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
146 lines (117 loc) · 4.63 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
const dropArea = document.getElementById('drop-area');
const bookEmojis = ['📕', '📙', '📒', '📗', '📘', '📓', '📔'];
function download(element, filename, contents) {
element.setAttribute('href', 'data:text/markdown;charset=utf-8,' + encodeURIComponent(contents));
element.setAttribute('download', filename);
element.classList.add("book-url")
}
dropArea.addEventListener('dragover', (event) => {
event.stopPropagation();
event.preventDefault();
// Style the drag-and-drop as a "copy file" operation.
event.dataTransfer.dropEffect = 'copy';
});
dropArea.addEventListener('drop', (event) => {
event.stopPropagation();
event.preventDefault();
const fileList = event.dataTransfer.files;
if (!validateType(fileList)) return null;
readFile(fileList[0]);
});
function validateType(fileList) {
for (const file of fileList) {
const type = file.type
if (type != 'text/plain') {
alert("Only .txt files are supported");
return false;
} else {
return true;
}
}
};
// Utility functions
const cleanUp = (str) => str.replace(/[\n\r]+/g, '');
const getAttribute = (attributes, index, regex = null) => {
let attr = cleanUp(attributes[index]);
return regex ? attr.split(regex).filter(Boolean)[1] : attr;
};
// Core functionality
function parseClippings(contents) {
const separator = '==========';
const timestampRegex = /Added on|Добавлено|Añadido el\:*/;
const clippings = contents.split(separator);
return clippings.map(clipping => {
const attributes = clipping.split("\n");
// Each clipping contains unnecessary auto-generated chunks of symbols like "\r" which we don't need and are not treating them as meaningful
const cleanedUpAttributes = attributes.filter(attr => attr !== "\r" && attr !== '');
// Skipping current clipping if no text is contained within a clipping, only datetime and book title
if (cleanedUpAttributes.length < 3) return null;
const title = getAttribute(cleanedUpAttributes, 0);
const timestamp = getAttribute(cleanedUpAttributes, 1, timestampRegex);
const text = getAttribute(cleanedUpAttributes, 2);
return {title: title, text: text, timestamp: timestamp};
}).filter(value => value);
}
function readFile(file) {
const reader = new FileReader();
reader.onload = function(event) {
try {
console.log("Reading the file");
const contents = event.target.result;
console.log("Parsing clippings");
const parsed = parseClippings(contents);
console.log("Grouping clippings by titles");
const groupByTitles = groupBy('title');
const grouped = groupByTitles(parsed);
booksTitles = Object.keys(grouped);
document.getElementById('separator').innerHTML = '. . .';
document.getElementById('status').innerHTML = '✨ Success! Found some clippings:';
console.log("Rendering book titles");
let bookIndex = 0;
for (const title in grouped) {
amountOfClippings = grouped[title].length;
renderBook(grouped, title, amountOfClippings, bookIndex);
(bookIndex >= bookEmojis.length - 1) ? bookIndex = 0 : bookIndex++;
}
console.log("Done!")
} catch(error) {
console.error(error); // this will log the error message to the console
}
};
reader.readAsText(file);
}
function renderBook (books, title, amountOfClippings, bookIndex) {
// create a new div element
var newDiv = document.createElement("div");
var anchor = document.createElement("a");
anchor.id = `book-${bookIndex}`
// and give it some content
var paragraph = document.createElement("p");
var newContent = document.createTextNode(`${bookEmojis[bookIndex]} ${title}: ${amountOfClippings}`);
// add the text node to the newly created div
paragraph.appendChild(newContent);
anchor.appendChild(paragraph);
newDiv.appendChild(anchor);
newDiv.classList.add("book");
// add the newly created element and its content into the DOM
var booksList = document.getElementById("books-list");
var firstChild = booksList.firstChild;
var contents = generateMarkdown(title, books);
var filename = title.replace(/\"/gi,"'").replace(/[\\\/"\*\:\?<>|]/gi, '');
download(anchor, `${filename}.md`, contents);
booksList.insertBefore(newDiv, firstChild);
}
function generateMarkdown(title, books) {
currentBook = books[title];
var str = ''
for (clipping of currentBook) {
str += `> ${clipping['text']}\n\n${clipping['timestamp']}\n\n`;
}
return str;
}
const groupBy = key => array =>
array.reduce((objectsByKeyValue, obj) => {
const value = obj[key];
objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
return objectsByKeyValue;
}, {});