Workflowy computable values

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

Από την 18/08/2016. Δείτε την τελευταία έκδοση.

Αυτός ο κώδικας δεν πρέπει να εγκατασταθεί άμεσα. Είναι μια βιβλιοθήκη για άλλους κώδικες που περιλαμβάνεται μέσω της οδηγίας meta // @require https://update.greatest.deepsurf.us/scripts/22313/142413/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.parentNode.parentNode.getAttribute('projectid')
  25. setTimeout(function () {
  26. itemOpenedOrClosed(restrictTo)
  27. }, 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 (restrictTo) {
  49. for (let i = 0; i < funcs.length; i++) {
  50. let script = funcs[i]
  51. execScript(script, restrictTo)
  52. }
  53. }
  54.  
  55. function execScript ({script, selector, id, color}, restrictTo) {
  56. let items = findItems(selector)
  57. for (let i = 0; i < items.length; i++) {
  58. let item = items[i]
  59. if (restrictTo && item.getAttribute('projectid') !== restrictTo) {
  60. continue
  61. }
  62. execForItem(item, script, id, color)
  63. }
  64. }
  65.  
  66. function execForItem (item, fun, id, color) {
  67. var children = []
  68. let par = item.querySelector('.children')
  69. for (let p = 0; p < par.children.length; p++) {
  70. if (par.children[p].classList.contains('project')) {
  71. children.push(par.children[p])
  72. }
  73. }
  74.  
  75. var args = []
  76. for (let i = 0; i < children.length; i++) {
  77. let child = children[i]
  78. arg = nodeToArg(child)
  79. args.push(arg)
  80. }
  81.  
  82. var result = item.querySelector('.result.script-' + id)
  83. if (!result) {
  84. let content = item.querySelector('.name .content')
  85. result = document.createElement('span')
  86. result.className = 'result script-' + id
  87. result.title = id
  88. result.style.color = color
  89. content.parentNode.insertBefore(result, content.nextSibling)
  90. }
  91. let resultvalue = fun(args, nodeToArg(item))
  92. result.innerHTML = (resultvalue || '').toString()
  93. }
  94.  
  95. function nodeToArg (node) {
  96. let name = node.querySelector('.name .content').innerText.trim()
  97. let note = node.querySelector('.notes').innerText.trim()
  98.  
  99. var arg = {name, note}
  100.  
  101. let results = node.querySelector('.name').querySelectorAll('.result')
  102. for (let r = 0; r < results.length; r++) {
  103. let result = results[r]
  104. arg[result.classList.item(1)] = result.innerText.trim()
  105. }
  106.  
  107. return arg
  108. }
  109.  
  110. function findItems (selector) {
  111. let parsed = parseSelector(selector)
  112. var items = null
  113. for (let l = 0; l < parsed.length; l++) {
  114. let layer = parsed[l]
  115. items = select(layer, items)
  116. }
  117. return items || []
  118. }
  119.  
  120. function select (layer, base) {
  121. if (!base) {
  122. base = document.querySelectorAll('.mainTreeRoot')
  123. }
  124.  
  125. let [connector, selector] = layer
  126. return getChildren(base, selector, connector === 'directchild')
  127. }
  128.  
  129. function getChildren (base, selector, onlydirect=false) {
  130. var filter
  131. switch (selector.type) {
  132. case 'id':
  133. filter = node =>
  134. node.getAttribute('projectid') === selector.val ||
  135. node.querySelector('.bullet').href.split('#/')[1] === selector.val
  136. break
  137. case 'regex':
  138. filter = node =>
  139. node.querySelector('.name .content').innerText.search(selector.val) !== -1
  140. break
  141. case 'name':
  142. filter = node =>
  143. node.querySelector('.name .content').innerText.trim() === selector.val
  144. break
  145. case 'any':
  146. filter = () => true
  147. break
  148. default:
  149. throw new Error('INVALID SELECTOR: ', selector)
  150. }
  151.  
  152. var children = []
  153. for (let i = 0; i < base.length; i++) {
  154. if (onlydirect) {
  155. let par = base[i].querySelector('.children')
  156. for (let p = 0; p < par.children.length; p++) {
  157. if (par.children[p].classList.contains('project') && par.children[p].classList.contains('open')) {
  158. children.push(par.children[p])
  159. }
  160. }
  161. } else {
  162. let all = base[i].querySelectorAll('.children > .project.open')
  163. for (let i = 0; i < all.length; i++) {
  164. children.push(all[i])
  165. }
  166. }
  167. }
  168.  
  169. return children.filter(filter)
  170. }
  171.  
  172. function registerScript (s) {
  173. funcs.push(s)
  174. }
  175.  
  176. function waitFor (selector, callback) {
  177. let res = document.querySelector(selector)
  178. if (res) return callback()
  179.  
  180. setTimeout(() => {
  181. waitFor(selector, callback)
  182. }, 1000)
  183. }