-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpanel.js
154 lines (133 loc) · 5.08 KB
/
panel.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
147
148
149
150
151
152
153
154
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('#convert').addEventListener('click', () => {
let textarea = document.querySelector('#markdown')
chrome.devtools.inspectedWindow.eval(`(${convertToMatrix.toString()})($0)`, matrix => {
if (matrix) {
let markdown = convertToMarkdown(matrix)
textarea.value = markdown
} else {
// there was some sort of error
textarea.value = `There was an issue. Please make sure that a table is selected.`
}
})
})
document.querySelector("#markdown").addEventListener('click', () => {
let markdown = document.querySelector("#markdown")
markdown.focus()
markdown.select()
})
})
/**
* Returns a 2D array of the HTML table provided.
* @param {HTMLElement} node - the table to convert to a matrix.
*/
const convertToMatrix = node => {
// if there's no node selected, hop out
if (!node) {
return false
}
// if the provided node isn't a table, climb to see if we can find one
if (!(node.nodeName.toLowerCase() === "table")) {
// We'll keep climbing until we either find a table or the top of the document
while(node.nodeName.toLowerCase() !== "table" && node.nodeName.toLowerCase !== "body"){
node = node.parentElement
}
}
// we'll check if a table was found
if (node.nodeName.toLowerCase() !== "table") {
return false
}
let header = node.querySelector('thead')
let header_row
// some html tables don't have headers, so we don't want to fail here
if (header) {
header_row = header.querySelector('tr')
}
let table_body = node.querySelector('tbody')
// Combine header row (if present) and body rows into an array
let rows = header_row ?
[header_row, ...table_body.children] :
[...table_body.children]
// This could be pulled as a setting from the UI
const span = true // if colspan and rowspan should be repeated
/**
* Here, we populate our matrix based on the HTML table.
*/
let tableMatrix
// This will cause rowspan and colspan elements to repeat
if (span) {
// set tableMatrix as empty arrays
tableMatrix = Array.from({ length: rows.length }, () => [])
rows.forEach((row, rowIndex) => {
[...row.children].forEach(tableElement => {
// grab the span attributes if present, or default to 1
let colspan = tableElement.getAttribute("colspan") || 1
let rowspan = tableElement.getAttribute("rowspan") || 1
// copy the elements into all cells that are spanned
for (let colCount = 0; colCount < colspan; colCount++) {
for (let rowCount = 0; rowCount < rowspan; rowCount++) {
tableMatrix[rowIndex + rowCount].push(tableElement.innerText.replace(/\n/g, ' '))
}
}
})
})
} else {
// map every item into a matrix
tableMatrix = rows.map(row => [...row.children].map(tableElement => tableElement.innerText))
}
// let the first row determine the column count
let columnCount = tableMatrix[0].length
// create an array for current max width of each column, default to 0
let columnWidths = Array(columnCount).fill(0)
// look at each row
tableMatrix.forEach(row => {
// check each column of that row
row.forEach((column, index) => {
// if the length of this column item is the largest in its column
if (column.length > columnWidths[index]) {
// set it as the new max column width
columnWidths[index] = column.length
}
})
})
return {
tableMatrix,
columnWidths
}
}
const convertToMarkdown = ({ tableMatrix, columnWidths }) => {
// This setting will add a blank header row in. Useful for HTML tables without headers.
let blankHeader = document.querySelector("#blank-header").checked
if (blankHeader) {
tableMatrix.unshift(Array(columnWidths.length).fill(''))
}
// This setting will remove all the extra spaces in the markdown table used to make things look nice.
let noPrettyPrint = document.querySelector("#no-pretty-print").checked
// Create the divider row that sits beneath the header
let divider = columnWidths.map(columnWidth => {
// stick to the minimum 3 if pretty printing turned off
if(noPrettyPrint){
return '---'
}
// (columnWidth || 1) ensures we'll always have at least 3 dashes, a req. for markdown
return '-'.repeat((columnWidth || 1) + 2)
})
// insert the divider after the header
tableMatrix.splice(1, 0, divider)
let markdown = tableMatrix.map(row => {
// create a row with all columns correctly spaced and joined together
let spacedRow = row.map((item, column) => {
// skip adding spaces if pretty print is turned off
if (noPrettyPrint) {
return item
}
// Column width must be a minimum of 3 to match the divider
let columnWidth = columnWidths[column] < 1 ? 3 : columnWidths[column] + 2
let leftSpace = ' '.repeat(Math.floor((columnWidth - item.length) / 2))
let rightSpace = ' '.repeat(Math.ceil((columnWidth - item.length) / 2))
return leftSpace + item + rightSpace
}).join('|')
return `|${spacedRow}|`
}).join('\n')
return markdown
}