wiki-plugin-mech 0.1.24 → 0.1.26

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 +135 -9
  2. package/package.json +1 -1
package/client/mech.js CHANGED
@@ -274,7 +274,8 @@
274
274
  function walk_emit ({elem,command,args,state}) {
275
275
  if(!('neighborhood' in state)) return trouble(elem,`WALK expects state.neighborhood, like from NEIGHBORS.`)
276
276
  inspect(elem,'neighborhood',state)
277
- const steps = walks(state.neighborhood)
277
+ const [,count,way] = command.match(/\b(\d+)? *(steps|days|weeks|months|hubs)\b/) || []
278
+ const steps = walks(count,way,state.neighborhood)
278
279
  const aspects = steps.filter(({graph})=>graph)
279
280
  if(state.debug) console.log({steps})
280
281
  elem.innerHTML = command
@@ -282,9 +283,16 @@
282
283
  elem.innerHTML += ` ⇒ ${aspects.length} aspects, ${nodes.length} nodes`
283
284
  if(steps.find(({graph}) => !graph)) trouble(elem,`WALK skipped sites with no links in sitemaps`)
284
285
  const item = elem.closest('.item')
285
- item.classList.add('aspect-source')
286
- item.aspectData = () => aspects
287
- state.aspect = [{id:item.dataset.id,result:aspects}]
286
+ if (aspects.length) {
287
+ state.aspect = state.aspect || []
288
+ const obj = state.aspect.find(obj => obj.id == elem.id)
289
+ if(obj) obj.result = aspects
290
+ else state.aspect.push({id:elem.id, result:aspects})
291
+ item.classList.add('aspect-source')
292
+ item.aspectData = () => state.aspect.map(obj => obj.result).flat()
293
+ if(state.debug) console.log({command,state:state.aspect,item:item.aspectData()})
294
+
295
+ }
288
296
  }
289
297
 
290
298
  function tick_emit ({elem,command,args,body,state}) {
@@ -666,6 +674,31 @@
666
674
  elem.innerHTML = command + ` ⇒ sent`
667
675
  }
668
676
 
677
+ function solo_emit({elem,command,state}) {
678
+ if(!('aspect' in state)) return trouble(elem,`"SOLO" expects "aspect" state, like from "WALK".`)
679
+ inspect(elem,'aspect',state)
680
+ const todo = state.aspect.map(each => ({
681
+ source:each.id,
682
+ aspects:each.result
683
+ }))
684
+ // from Solo plugin, client/solo.js
685
+ const pageKey = elem.closest('.page').dataset.key
686
+ const doing = {type:'batch', sources:todo, pageKey}
687
+ console.log({pageKey,doing})
688
+ const popup = window.open('/plugins/solo/dialog/#','solo','popup,height=720,width=1280')
689
+ if (popup.location.pathname != '/plugins/solo/dialog/'){
690
+ console.log('launching new dialog')
691
+ popup.addEventListener('load', event => {
692
+ console.log('launched and loaded')
693
+ popup.postMessage(doing, window.origin)
694
+ })
695
+ }
696
+ else {
697
+ console.log('reusing existing dialog')
698
+ popup.postMessage(doing, window.origin)
699
+ }
700
+ }
701
+
669
702
 
670
703
  // C A T A L O G
671
704
 
@@ -694,7 +727,8 @@
694
727
  ROSTER: {emit:roster_emit},
695
728
  LINEUP: {emit:lineup_emit},
696
729
  LISTEN: {emit:listen_emit},
697
- MESSAGE: {emit:message_emit}
730
+ MESSAGE: {emit:message_emit},
731
+ SOLO: {emit:solo_emit}
698
732
  }
699
733
 
700
734
 
@@ -777,14 +811,23 @@
777
811
  }
778
812
 
779
813
  // inspired by aspects-of-recent-changes/roster-graphs.html
780
- function walks(neighborhood) {
814
+ function walks(count,way='steps',neighborhood) {
815
+ const find = slug => neighborhood.find(info => info.slug == slug)
781
816
  const prob = n => Math.floor(n * Math.abs(Math.random()-Math.random()))
782
817
  const rand = a => a[prob(a.length)]
783
818
  const domains = neighborhood
784
819
  .map(info => info.domain)
785
820
  .filter(uniq)
786
- return domains
787
- .map(domain => {
821
+ switch(way) {
822
+ case 'steps': return steps(count)
823
+ case 'days': return periods(way,1,count)
824
+ case 'weeks': return periods(way,7,count)
825
+ case 'months': return periods(way,30,count)
826
+ case 'hubs': return hubs(count)
827
+ }
828
+
829
+ function steps(count=5) {
830
+ return domains.map(domain => {
788
831
  const name = domain.split('.').slice(0,3).join('.')
789
832
  const done = new Set()
790
833
  const graph = new Graph()
@@ -792,7 +835,6 @@
792
835
  const here = neighborhood
793
836
  .filter(info => info.domain==domain && ('links' in info))
794
837
  if(!here.length) return {name,graph:null}
795
- const find = slug => neighborhood.find(info => info.slug == slug)
796
838
  const node = info => {
797
839
  nid = graph.addNode('',{
798
840
  name:info.title.replaceAll(/ /g,"\n"),
@@ -803,6 +845,7 @@
803
845
  const rel = (here,there) => graph.addRel('',here,there)
804
846
  const links = nid => graph.nodes[nid].props.links.filter(slug => !done.has(slug))
805
847
  const start = rand(here)
848
+ // const start = find('welcome-visitors')
806
849
  done.add(start.slug)
807
850
  node(start)
808
851
  for (let n=5;n>0;n--) {
@@ -816,6 +859,84 @@
816
859
  }
817
860
  return {name,graph}
818
861
  })
862
+ }
863
+
864
+ function periods(way,days,count=12) {
865
+ const interval = days*24*60*60*1000
866
+ const iota = [...Array(Number(count)).keys()]
867
+ const dates = iota.map(n => Date.now()-n*interval)
868
+ const aspects = []
869
+ for(const stop of dates) {
870
+ const start = stop-interval
871
+ const name = `${way.replace(/s$/,'')} ${new Date(start).toLocaleDateString()}`
872
+ const graph = new Graph()
873
+ const node = info => {
874
+ return graph.addUniqNode('',{
875
+ name:info.title.replaceAll(/ /g,"\n"),
876
+ title:info.title,
877
+ site:info.domain
878
+ })
879
+ }
880
+ const here = neighborhood
881
+ .filter(info => info.date < stop && info.date >= start)
882
+ .filter(info => !(info.links && Object.keys(info.links).length > 5))
883
+ if(here.length) {
884
+ for (const info of here) {
885
+ const nid = node(info)
886
+ for (const link in (info.links||{})) {
887
+ const linked = find(link)
888
+ if(linked)
889
+ graph.addRel('',nid,node(linked))
890
+ }
891
+ }
892
+ aspects.push({name,graph})
893
+ }
894
+ }
895
+ return aspects
896
+ }
897
+
898
+ function hubs(count=12) {
899
+ const aspects = []
900
+ const ignored = new Set()
901
+ const hits = {}
902
+ for (const info of neighborhood)
903
+ if(info.links)
904
+ if(Object.keys(info.links).length <= 15) {
905
+ for(const link in info.links)
906
+ if(find(link))
907
+ hits[link] = (hits[link]||0) + 1
908
+ } else {
909
+ ignored.add(info.slug)
910
+ }
911
+ if(ignored.size > 0)
912
+ console.log('hub links ignored for large pages:',[...ignored])
913
+ const hubs = Object.entries(hits)
914
+ .sort((a,b) => b[1]-a[1])
915
+ .slice(0,count)
916
+ console.log({hits,hubs})
917
+
918
+ for(const hub of hubs) {
919
+ const name = `hub ${hub[1]} ${hub[0]}`
920
+ const graph = new Graph()
921
+ const node = info => {
922
+ return graph.addUniqNode('',{
923
+ name:info.title.replaceAll(/ /g,"\n"),
924
+ title:info.title,
925
+ site:info.domain
926
+ })
927
+ }
928
+ const info = find(hub[0])
929
+ const nid = node(info)
930
+ for(const link in (info.links||{})) {
931
+ const linked = find(link)
932
+ if(linked)
933
+ graph.addRel('',nid,node(linked))
934
+ }
935
+ aspects.push({name,graph})
936
+ }
937
+ return aspects
938
+ }
939
+
819
940
  }
820
941
 
821
942
 
@@ -865,6 +986,11 @@
865
986
  return this.nodes.length-1;
866
987
  }
867
988
 
989
+ addUniqNode(type, props={}) {
990
+ const nid = this.nodes.findIndex(node => node.type == type && node.props?.name == props?.name)
991
+ return nid >= 0 ? nid : this.addNode(type, props)
992
+ }
993
+
868
994
  addRel(type, from, to, props={}) {
869
995
  const obj = {type, from, to, props};
870
996
  this.rels.push(obj);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-plugin-mech",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "Federated Wiki - Mechanism Scripting Plugin",
5
5
  "keywords": [
6
6
  "mech",