Workflowy computable values

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

当前为 2016-08-15 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/22313/141760/Workflowy%20computable%20values.js

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

QingJ © 2025

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