wiki-plugin-mech 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/client/mech.js +115 -3
  2. package/package.json +1 -1
package/client/mech.js CHANGED
@@ -1,6 +1,8 @@
1
1
 
2
2
  (function() {
3
3
 
4
+ const uniq = (value, index, self) => self.indexOf(value) === index
5
+
4
6
  function expand(text) {
5
7
  return text
6
8
  .replace(/&/g, '&')
@@ -48,6 +50,7 @@
48
50
  }
49
51
 
50
52
  function trouble(elem,message) {
53
+ if(elem.innerText.match(/✖︎/)) return
51
54
  elem.innerHTML += `<button style="border-width:0;color:red;">✖︎</button>`
52
55
  elem.querySelector('button').addEventListener('click',event => {
53
56
  elem.outerHTML += `<span style="width:80%;color:gray;">${message}</span>` })
@@ -57,7 +60,10 @@
57
60
  if(elem.innerHTML.match(/button/)) return
58
61
  if (!body?.length) return trouble(elem,'CLICK expects indented blocks to follow.')
59
62
  elem.innerHTML += '<button style="border-width:0;">◉</button>'
60
- elem.querySelector('button').addEventListener('click',event => run(body,state))
63
+ elem.querySelector('button').addEventListener('click',event => {
64
+ state.debug = event.shiftKey
65
+ run(body,state)
66
+ })
61
67
  }
62
68
 
63
69
  function hello_emit ({elem,args}) {
@@ -97,6 +103,7 @@
97
103
  fetch(url)
98
104
  .then (res => res.json())
99
105
  .then (data => {
106
+ if(state.debug) console.log({sensor,data})
100
107
  elem.innerHTML = line + ' ⌛'
101
108
  const value = f(avg(Object.values(data)))
102
109
  state.temperature = `${value.toFixed(2)}°F`
@@ -110,12 +117,73 @@
110
117
  elem.innerHTML = command + `<br><font face=Arial size=32>${value}</font>`
111
118
  }
112
119
 
120
+ function source_emit ({elem,command,args,body,state}) {
121
+ if (!(args && args.length)) return trouble(elem,`Expected Source topic, like "markers" for Map markers.`)
122
+ const topic = args[0]
123
+ const sources = requestSourceData(state.$item, topic)
124
+ if(!sources.length) return trouble(elem,`Expected source for "${topic}" in the lineup.`)
125
+ const count = type => {
126
+ const count = sources
127
+ .filter(source => [...source.div.classList].includes(type))
128
+ .length
129
+ return count ? `${count} ${type}` : null}
130
+ const counts = [count('map'),count('image'),count('frame')]
131
+ .filter(count => count)
132
+ .join(", ")
133
+ if (state.debug) console.log({topic,sources})
134
+ elem.innerHTML = command + ' ⇒ ' + counts
135
+ state[topic] = sources
136
+ if (body) run(body,state)
137
+ }
138
+
139
+ function preview_emit ({elem,command,args,state}) {
140
+ const round = digits => (+digits).toFixed(7)
141
+ const story = []
142
+ for (const arg of args) {
143
+ switch (arg) {
144
+ case 'map':
145
+ if(!('marker' in state)) return trouble(elem,`"map" preview expects "marker" state, like from "SOURCE marker".`)
146
+ const text = state.marker
147
+ .map(marker => [marker.result])
148
+ .flat(2)
149
+ .map(latlon => `${round(latlon.lat)}, ${round(latlon.lon)} ${latlon.label||''}`)
150
+ .filter(uniq)
151
+ .join("\n")
152
+ story.push({type:'map',text})
153
+ break
154
+ case 'graph':
155
+ if(!('aspect' in state)) return trouble(elem,`"graph" preview expects "aspect" state, like from "SOURCE aspect".`)
156
+ for (const {div,result} of state.aspect) {
157
+ for (const {name,graph} of result) {
158
+ if(state.debug) console.log({div,result,name,graph})
159
+ story.push({type:'paragraph',text:name})
160
+ story.push({type:'graphviz',text:dotify(graph)})
161
+ }
162
+ story.push({type:'pagefold',text:'.'})
163
+ }
164
+ break
165
+ case 'synopsis':
166
+ {const text = `This page has been generated by the Mech plugin. We want to tell you where. That's coming soon.`
167
+ story.push({type:'paragraph',text})}
168
+ break
169
+ default:
170
+ return trouble(elem,`"${arg}" doesn't name an item we can preview`)
171
+ }
172
+ }
173
+ const title = "Mech Preview"
174
+ const page = {title,story}
175
+ const options = {}
176
+ wiki.showResult(wiki.newPage(page), options)
177
+ }
178
+
113
179
  const blocks = {
114
180
  CLICK: {emit:click_emit, bind:null},
115
181
  HELLO: {emit:hello_emit, bind:null},
116
182
  FROM: {emit:from_emit, bind:null},
117
183
  SENSOR: {emit:sensor_emit, bind:null},
118
- REPORT: {emit:report_emit, bind:null}
184
+ REPORT: {emit:report_emit, bind:null},
185
+ SOURCE: {emit:source_emit, bind:null},
186
+ PREVIEW: {emit:preview_emit, bind:null}
119
187
  }
120
188
 
121
189
  function run (nest,state={}) {
@@ -129,6 +197,7 @@
129
197
  const next = scope[0]
130
198
  const body = next && ('command' in next) ? null : scope.shift()
131
199
  const stuff = {command,op,args,body,elem,state}
200
+ if(state.debug) console.log(stuff)
132
201
  if (blocks[op])
133
202
  blocks[op].emit.apply(null,[stuff])
134
203
  else
@@ -146,8 +215,9 @@
146
215
  const lines = item.text.split(/\n/)
147
216
  const nest = tree(lines,[],0)
148
217
  const html = format(nest)
218
+ const state = {$item}
149
219
  $item.append(`<div style="background-color:#eee;padding:15px;border-top:8px;">${html}</div>`)
150
- run(nest)
220
+ run(nest,state)
151
221
  }
152
222
 
153
223
  function bind($item, item) {
@@ -164,4 +234,46 @@
164
234
  module.exports = {expand}
165
235
  }
166
236
 
237
+
238
+ // library functions
239
+
240
+ // adapted from wiki-plugin-frame/client/frame.js
241
+ function requestSourceData($item, topic) {
242
+ let sources = []
243
+ for (let div of document.querySelectorAll(`.item`)) {
244
+ if (div.classList.contains(`${topic}-source`)) {
245
+ sources.unshift(div)
246
+ }
247
+ if (div === $item.get(0)) {
248
+ break
249
+ }
250
+ }
251
+
252
+ return sources.map(div => {
253
+ let getData = div[`${topic}Data`]
254
+ let result = getData ? getData() : null
255
+ return {div,result}
256
+ })
257
+ }
258
+
259
+ // adapted from super-collaborator/dotify.js
260
+ function dotify(graph) {
261
+ const tip = props => Object.entries(props).filter(e => e[1]).map(e => `${e[0]}: ${e[1]}`).join("\\n")
262
+ const nodes = graph.nodes.map((node,id) => {
263
+ const label = `${node.type}\\n${node.props.name}`
264
+ return `${id} [label="${label}" ${(node.props.url||node.props.tick)?`URL="${node.props.url||'#'}" target="_blank"`:''} tooltip="${tip(node.props)}"]`
265
+ })
266
+ const edges = graph.rels.map(rel => {
267
+ return `${rel.from}->${rel.to} [label="${rel.type}" labeltooltip="${tip(rel.props)}"]`
268
+ })
269
+ return [
270
+ 'digraph {',
271
+ 'rankdir=LR',
272
+ 'node [shape=box style=filled fillcolor=palegreen]',
273
+ ...nodes,
274
+ ...edges,
275
+ '}'].join("\n")
276
+ }
277
+
278
+
167
279
  }).call(this)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-plugin-mech",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Federated Wiki - Mechanism Scripting Plugin",
5
5
  "keywords": [
6
6
  "mech",