Workflowy computable values

Compute things with sublists and display values on an item name.

目前為 2016-08-18 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/22313/142414/Workflowy%20computable%20values.js

  1. var parseSelector = window.Parser.parse
  2.  
  3. window.funcs = []
  4. window.nodeCache = {}
  5. var observer
  6.  
  7. // observe dom mutations to make it run every time an item is opened / closed
  8. function start () {
  9. GM_addStyle(`
  10. .project .content {
  11. display: inline-block !important;
  12. }
  13.  
  14. .project .result {
  15. display: inline;
  16. color: blue;
  17. margin-left: 10px;
  18. }
  19. `)
  20.  
  21.  
  22. document.body.addEventListener('click', function (e) {
  23. if (e.target.id === 'expandButton') {
  24. let restrictTo = e.target.parentNode.parentNode.getAttribute('projectid')
  25. setTimeout(function () {
  26. itemOpenedOrClosed(restrictTo)
  27. }, 1000)
  28. }
  29. })
  30.  
  31. itemOpenedOrClosed()
  32. }
  33.  
  34. function itemOpenedOrClosed (restrictTo) {
  35. for (let i = 0; i < funcs.length; i++) {
  36. let script = funcs[i]
  37. execScript(script, restrictTo)
  38. }
  39. }
  40.  
  41. function execScript ({script, selector, id, color}, restrictTo) {
  42. let items = findItems(selector)
  43. for (let i = 0; i < items.length; i++) {
  44. let item = items[i]
  45. if (restrictTo && item.getAttribute('projectid') !== restrictTo) {
  46. continue
  47. }
  48. execForItem(item, script, id, color)
  49. }
  50. }
  51.  
  52. function execForItem (item, fun, id, color) {
  53. var children = []
  54. let par = item.querySelector('.children')
  55. for (let p = 0; p < par.children.length; p++) {
  56. if (par.children[p].classList.contains('project')) {
  57. children.push(par.children[p])
  58. }
  59. }
  60.  
  61. var args = []
  62. for (let i = 0; i < children.length; i++) {
  63. let child = children[i]
  64. arg = nodeToArg(child)
  65. args.push(arg)
  66. }
  67.  
  68. var result = item.querySelector('.result.script-' + id)
  69. if (!result) {
  70. let content = item.querySelector('.name .content')
  71. result = document.createElement('span')
  72. result.className = 'result script-' + id
  73. result.title = id
  74. result.style.color = color
  75. content.parentNode.insertBefore(result, content.nextSibling)
  76. }
  77. let resultvalue = fun(args, nodeToArg(item))
  78. result.innerHTML = (resultvalue || '').toString()
  79. }
  80.  
  81. function nodeToArg (node) {
  82. let name = node.querySelector('.name .content').innerText.trim()
  83. let note = node.querySelector('.notes').innerText.trim()
  84.  
  85. var arg = {name, note}
  86.  
  87. let results = node.querySelector('.name').querySelectorAll('.result')
  88. for (let r = 0; r < results.length; r++) {
  89. let result = results[r]
  90. arg[result.classList.item(1)] = result.innerText.trim()
  91. }
  92.  
  93. return arg
  94. }
  95.  
  96. function findItems (selector) {
  97. let parsed = parseSelector(selector)
  98. var items = null
  99. for (let l = 0; l < parsed.length; l++) {
  100. let layer = parsed[l]
  101. items = select(layer, items)
  102. }
  103. return items || []
  104. }
  105.  
  106. function select (layer, base) {
  107. if (!base) {
  108. base = document.querySelectorAll('.mainTreeRoot')
  109. }
  110.  
  111. let [connector, selector] = layer
  112. return getChildren(base, selector, connector === 'directchild')
  113. }
  114.  
  115. function getChildren (base, selector, onlydirect=false) {
  116. var filter
  117. switch (selector.type) {
  118. case 'id':
  119. filter = node =>
  120. node.getAttribute('projectid') === selector.val ||
  121. node.querySelector('.bullet').href.split('#/')[1] === selector.val
  122. break
  123. case 'regex':
  124. filter = node =>
  125. node.querySelector('.name .content').innerText.search(selector.val) !== -1
  126. break
  127. case 'name':
  128. filter = node =>
  129. node.querySelector('.name .content').innerText.trim() === selector.val
  130. break
  131. case 'any':
  132. filter = () => true
  133. break
  134. default:
  135. throw new Error('INVALID SELECTOR: ', selector)
  136. }
  137.  
  138. var children = []
  139. for (let i = 0; i < base.length; i++) {
  140. if (onlydirect) {
  141. let par = base[i].querySelector('.children')
  142. for (let p = 0; p < par.children.length; p++) {
  143. if (par.children[p].classList.contains('project') && par.children[p].classList.contains('open')) {
  144. children.push(par.children[p])
  145. }
  146. }
  147. } else {
  148. let all = base[i].querySelectorAll('.children > .project.open')
  149. for (let i = 0; i < all.length; i++) {
  150. children.push(all[i])
  151. }
  152. }
  153. }
  154.  
  155. return children.filter(filter)
  156. }
  157.  
  158. function registerScript (s) {
  159. funcs.push(s)
  160. }
  161.  
  162. function waitFor (selector, callback) {
  163. let res = document.querySelector(selector)
  164. if (res) return callback()
  165.  
  166. setTimeout(() => {
  167. waitFor(selector, callback)
  168. }, 1000)
  169. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址