yuque-uc-table.user.js 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // ==UserScript==
  2. // @name YuQue (UC) Table Transformer
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1
  5. // @description try to take over the world!
  6. // @author You
  7. // @match https://www.yuque.com/siyou-lmowq/*
  8. // @grant GM_setClipboard
  9. // ==/UserScript==
  10. (function() {
  11. 'use strict';
  12. const regexpGeneric = /^(?:List|Set)<([^>]+)>$/i
  13. const convertType = (type) => {
  14. let isList = false
  15. if (type.endsWith('[]')) {
  16. isList = true
  17. type = type.substring(0, type.length - 2)
  18. } else if (regexpGeneric.test(type)) {
  19. isList = true
  20. type = regexpGeneric.exec(type)[1]
  21. }
  22. switch (type.toLowerCase()) {
  23. case 'long':
  24. case 'float':
  25. case 'double':
  26. case 'int':
  27. case 'integer': type = 'number'; break
  28. case 'boolean': type = 'boolean'; break
  29. case 'string': type = 'string'; break
  30. }
  31. if (isList) type += '[]'
  32. return type
  33. }
  34. const parseRow = (row) => {
  35. const tds = row.querySelectorAll('td')
  36. if (tds.length < 3) return ''
  37. const name = tds[0].innerText.trim()
  38. if (!name) return ''
  39. const type = tds[1].innerText.trim()
  40. const comment = tds[2].innerText.trim()
  41. return ` ${name.replace(/\n/g, '')}: ${convertType(type)} // ${comment.replace(/\n/g, ' ')}\n`
  42. }
  43. const parseRows = (header, rows) => {
  44. if (!rows.length) return
  45. let content = `interface ${header} {\n`
  46. rows.forEach(row => {
  47. content += parseRow(row)
  48. })
  49. content += '}'
  50. GM_setClipboard(content)
  51. return content
  52. }
  53. const parseTable = (tableDiv, header) => {
  54. const result = document.createElement('pre')
  55. result.append(document.createTextNode(parseRows(header, tableDiv.querySelectorAll('tr:nth-child(n+2)'))))
  56. tableDiv.prepend(result)
  57. }
  58. const createButton = (container, header) => {
  59. container.dataset.dump = true
  60. container.style.position = 'relative'
  61. const btn = document.createElement('button')
  62. btn.append(document.createTextNode('Dump'))
  63. btn.addEventListener('click', () => {
  64. parseTable(container, header)
  65. btn.remove()
  66. })
  67. btn.style.position = 'absolute'
  68. btn.style.top = '0'
  69. btn.style.right = '-2em'
  70. btn.style.zIndex = 10000
  71. container.prepend(btn)
  72. }
  73. const searchHeader = (element, tagName) => {
  74. do {
  75. element = element?.previousElementSibling
  76. if (element?.tagName === tagName) return element
  77. } while (element?.tagName)
  78. }
  79. const ob = new MutationObserver(mutations => {
  80. mutations.forEach(({ target }) => {
  81. if (target?.tagName === 'NE-TABLE-HOLE' && !target?.dataset?.dump) {
  82. setTimeout(() => {
  83. const header = searchHeader(target, 'NE-H3')?.innerText?.trim()
  84. if (header) createButton(target, header)
  85. }, 1000)
  86. }
  87. })
  88. })
  89. ob.observe(document.body, { subtree: true, childList: true })
  90. })();