|
|
@@ -0,0 +1,95 @@
|
|
|
+// ==UserScript==
|
|
|
+// @name YuQue (UC) Table Transformer
|
|
|
+// @namespace http://tampermonkey.net/
|
|
|
+// @version 1.1
|
|
|
+// @description try to take over the world!
|
|
|
+// @author You
|
|
|
+// @match https://www.yuque.com/siyou-lmowq/*
|
|
|
+// @grant GM_setClipboard
|
|
|
+// ==/UserScript==
|
|
|
+
|
|
|
+(function() {
|
|
|
+ 'use strict';
|
|
|
+ const regexpGeneric = /^(?:List|Set)<([^>]+)>$/i
|
|
|
+ const convertType = (type) => {
|
|
|
+ let isList = false
|
|
|
+ if (type.endsWith('[]')) {
|
|
|
+ isList = true
|
|
|
+ type = type.substring(0, type.length - 2)
|
|
|
+ } else if (regexpGeneric.test(type)) {
|
|
|
+ isList = true
|
|
|
+ type = regexpGeneric.exec(type)[1]
|
|
|
+ }
|
|
|
+ switch (type.toLowerCase()) {
|
|
|
+ case 'long':
|
|
|
+ case 'float':
|
|
|
+ case 'double':
|
|
|
+ case 'int':
|
|
|
+ case 'integer': type = 'number'; break
|
|
|
+ case 'boolean': type = 'boolean'; break
|
|
|
+ case 'string': type = 'string'; break
|
|
|
+ }
|
|
|
+ if (isList) type += '[]'
|
|
|
+ return type
|
|
|
+ }
|
|
|
+ const parseRow = (row) => {
|
|
|
+ const tds = row.querySelectorAll('td')
|
|
|
+ if (tds.length < 3) return ''
|
|
|
+ const name = tds[0].innerText.trim()
|
|
|
+ if (!name) return ''
|
|
|
+ const type = tds[1].innerText.trim()
|
|
|
+ const comment = tds[2].innerText.trim()
|
|
|
+ return ` ${name.replace(/\n/g, '')}: ${convertType(type)} // ${comment.replace(/\n/g, ' ')}\n`
|
|
|
+ }
|
|
|
+ const parseRows = (header, rows) => {
|
|
|
+ if (!rows.length) return
|
|
|
+ let content = `interface ${header} {\n`
|
|
|
+ rows.forEach(row => {
|
|
|
+ content += parseRow(row)
|
|
|
+ })
|
|
|
+ content += '}'
|
|
|
+ GM_setClipboard(content)
|
|
|
+ return content
|
|
|
+ }
|
|
|
+
|
|
|
+ const parseTable = (tableDiv, header) => {
|
|
|
+ const result = document.createElement('pre')
|
|
|
+ result.append(document.createTextNode(parseRows(header, tableDiv.querySelectorAll('tr:nth-child(n+2)'))))
|
|
|
+ tableDiv.prepend(result)
|
|
|
+ }
|
|
|
+
|
|
|
+ const createButton = (container, header) => {
|
|
|
+ container.dataset.dump = true
|
|
|
+ container.style.position = 'relative'
|
|
|
+ const btn = document.createElement('button')
|
|
|
+ btn.append(document.createTextNode('Dump'))
|
|
|
+ btn.addEventListener('click', () => {
|
|
|
+ parseTable(container, header)
|
|
|
+ btn.remove()
|
|
|
+ })
|
|
|
+ btn.style.position = 'absolute'
|
|
|
+ btn.style.top = '0'
|
|
|
+ btn.style.right = '-2em'
|
|
|
+ btn.style.zIndex = 10000
|
|
|
+ container.prepend(btn)
|
|
|
+ }
|
|
|
+ const searchHeader = (element, tagName) => {
|
|
|
+ do {
|
|
|
+ element = element?.previousElementSibling
|
|
|
+ if (element?.tagName === tagName) return element
|
|
|
+ } while (element?.tagName)
|
|
|
+ }
|
|
|
+
|
|
|
+ const ob = new MutationObserver(mutations => {
|
|
|
+ mutations.forEach(({ target }) => {
|
|
|
+ if (target?.tagName === 'NE-TABLE-HOLE' && !target?.dataset?.dump) {
|
|
|
+ setTimeout(() => {
|
|
|
+ const header = searchHeader(target, 'NE-H3')?.innerText?.trim()
|
|
|
+ if (header) createButton(target, header)
|
|
|
+ }, 1000)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ ob.observe(document.body, { subtree: true, childList: true })
|
|
|
+
|
|
|
+})();
|