ModeConnections.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. var m = require('mithril');
  2. // https://github.com/markdown-it/markdown-it
  3. var markdown = require('markdown-it')()
  4. .use(require('markdown-it-footnote'));
  5. var _dbs = require('./dbs');
  6. var _Header = require('./header');
  7. var _Footer = require('./footer');
  8. var _Ui = require('./ui.js');
  9. // ____ __
  10. // / __ \____ / /_
  11. // / / / / __ \/ __/
  12. // / /_/ / /_/ / /_
  13. // /_____/\____/\__/
  14. var _Dot = {
  15. id:null,
  16. dottype:null,
  17. type:'',
  18. title:'',
  19. breadcrumb:'',
  20. text:'',
  21. summary:'',
  22. active:true,
  23. opened:0,
  24. nested:false,
  25. links:null,
  26. parents:[],
  27. lang:null,
  28. setupTitle(vn){
  29. this.title = vn.attrs.title;
  30. if(!this.title) this.title = this.type;
  31. if(this.title)
  32. this.title = markdown.renderInline(this.title);
  33. },
  34. setuptext(vn){
  35. // console.log('setuptext', vn);
  36. // construct text
  37. this.text = vn.attrs.text || '';
  38. this.rendered_text = markdown.render(this.text);
  39. if(this.dottype == "preface"){
  40. this.summary = this.rendered_text;
  41. }else{
  42. // construct summary
  43. // TODO: summary needs more work (strip tags, markdown render)
  44. // remove img
  45. this.summary = this.text.replace(/!\[[^\]]+\]\([^\)]+\)/g, "");
  46. // get portion of text
  47. // this.summary = this.summary.match('([^ ]*[ ]{0,1}){1,6}')[0];
  48. // https://stackoverflow.com/questions/5454235/shorten-string-without-cutting-words-in-javascript
  49. // this.summary = this.summary.replace(/^(.{18}[^\s]*).*/, "$1");
  50. this.summary = this.summary.substr(0, this.summary.lastIndexOf(' ', 30));
  51. // end underscores (italic) splited by summarizing
  52. this.summary = this.summary.trim().replace(/_([^_]+)$/g, "_$1_");
  53. // remove brackets (links) splited by summarizing
  54. this.summary = this.summary.replace(/\[([^\]]+)$/g, "$1");
  55. // render the markdown
  56. this.summary = markdown.renderInline(this.summary) + " …";
  57. }
  58. },
  59. oninit(vn){
  60. this.id = vn.attrs.id;
  61. this.type = vn.attrs.type;
  62. this.level = vn.attrs.level;
  63. this.dottype = vn.attrs.dottype;
  64. this.breadcrumb = vn.attrs.breadcrumb;
  65. // console.log(`${this.id} -> ${this.dottype}`);
  66. if(typeof vn.attrs.active !== 'undefined')
  67. this.active = vn.attrs.active;
  68. // links
  69. this.links = _dbs.data_strct[this.id];
  70. // parents memorize where do we come from to avoid duplicates and looping nav
  71. if(vn.attrs.parents){
  72. this.parents = this.parents.concat(vn.attrs.parents);
  73. // console.log('_Dot init '+this.id+' parents :',this.parents);
  74. }
  75. this.nested = this.parents.length ? true : false;
  76. // if(this.nested) console.log(`oninit ${this.id}`);
  77. this.lang = vn.attrs.lang;
  78. this.setupTitle(vn);
  79. this.setuptext(vn);
  80. },
  81. oncreate(vn){
  82. if(this.active){
  83. vn.dom.classList.remove('disabled');
  84. }else{
  85. vn.dom.classList.add('disabled');
  86. }
  87. },
  88. onbeforeupdate(vn){
  89. if(this.lang != vn.attrs.lang){
  90. this.lang = vn.attrs.lang;
  91. this.breadcrumb = vn.attrs.breadcrumb;
  92. this.type = vn.attrs.type;
  93. this.setuptext(vn);
  94. this.setupTitle(vn);
  95. }
  96. },
  97. onupdate(vn){
  98. // if(this.nested) console.log(`onupdate ${this.id}`);
  99. if(this.active){
  100. if (this.opened){
  101. vn.dom.classList.add('opened');
  102. if(this.links.to.length)
  103. vn.dom.classList.add('to-links');
  104. if(this.links.from.length)
  105. vn.dom.classList.add('from-links');
  106. }else{
  107. vn.dom.classList.remove('opened');
  108. }
  109. }
  110. },
  111. setupLinks(vn, c, links){
  112. return m('nav', {'class':`links ${c}`}, links.map(id => {
  113. // console.log(id);
  114. if(typeof _dbs.data_byid[this.lang][id] !== 'undefined'){
  115. var obj = _dbs.data_byid[this.lang][id];
  116. // console.log('link to : obj', obj);
  117. return m(_Dot, {
  118. "id":id,
  119. 'title':obj.title,
  120. // TODO: translate breadcrumb
  121. 'breadcrumb':obj.breadcrumb,
  122. 'text':obj.text,
  123. 'dottype':obj.dottype,
  124. 'type':obj.type,
  125. // passe the memory of crossed dots plus the current one
  126. 'parents':vn.state.parents.concat([vn.state.id]),
  127. // activate link only if not in parents (already went through it)
  128. 'active':vn.state.parents.indexOf(id) == -1 ? true:false,
  129. // 'nested':true,
  130. 'lang':this.lang,
  131. });
  132. }
  133. })
  134. );
  135. },
  136. viewOpenedContent(vn){
  137. return m('div', {
  138. 'uid':this.id,
  139. 'class':`dot ${this.dottype}${this.nested ? ' nested':''}`},
  140. [
  141. // links to
  142. this.links.to.length
  143. ? this.setupLinks(vn, 'to', this.links.to)
  144. : null, // if no links to, add nothing
  145. // close btn
  146. m('div', {
  147. 'class':'close-link-btn',
  148. onclick(e){
  149. vn.state.opened = 0;
  150. }
  151. }//, m('span') // , m.trust("🗙")
  152. ),
  153. // Title
  154. m('span', {'class':'title'}, m.trust(this.nested || _dbs.active_type_filter ? this.breadcrumb : this.title)),
  155. // full text
  156. m('section', {
  157. 'class':'text',
  158. onmouseover(e){
  159. e.preventDefault();
  160. if(e.target.nodeName == "A" ){
  161. let id = e.target.getAttribute("href");
  162. // add highlight class
  163. vn.dom.querySelector(`nav.links>div[uid="${id}"]`).classList.add('highlight');
  164. }else{
  165. // remove all hilight class
  166. for (let link of vn.dom.querySelectorAll('nav.links>div.dot')) {
  167. link.classList.remove('highlight');
  168. }
  169. }
  170. },
  171. onclick(e){
  172. e.preventDefault();
  173. if(e.target.nodeName == "A" ){
  174. let id = e.target.getAttribute("href");
  175. vn.dom.querySelector(`nav.links>div[uid="${id}"]>.title`).click();
  176. }
  177. }
  178. }, m.trust(this.rendered_text)
  179. ),
  180. // links from
  181. this.links.from.length
  182. ? this.setupLinks(vn, 'from', this.links.from)
  183. : null, // if no links from, add nothing
  184. ]
  185. );
  186. },
  187. viewPreviewContent(vn){
  188. return m('div', {
  189. 'uid':this.id,
  190. 'class':`dot ${this.dottype}${this.nested ? ' nested':''}`
  191. },
  192. [
  193. // bullet
  194. m('div', {'class':'bullet'}, m('span', m.trust('⚫'))),
  195. m('span', {
  196. 'class':'title',
  197. onclick(e){
  198. if(!vn.state.opened) vn.state.opened = 1;
  199. }
  200. }, m.trust(this.nested || _dbs.active_type_filter ? this.breadcrumb : this.title)),
  201. m('p', {
  202. 'class':'summary',
  203. onclick(e){
  204. if(!vn.state.opened) vn.state.opened = 1;
  205. }
  206. }, m.trust(this.summary))
  207. ]
  208. );
  209. },
  210. view(vn){
  211. return this.active && vn.state.opened
  212. ? this.viewOpenedContent(vn) // full view of dot with linked dots
  213. : this.viewPreviewContent(vn); // preview dot
  214. }
  215. }
  216. /*
  217. full list of black dotlikes from unicode
  218. ● - ● - Black Circle
  219. ⏺ - ⏺ - Black Circle for Record
  220. ⚫ - ⚫ - Medium Black Circle
  221. ⬤ - ⬤ - Black Large Circle
  222. ⧭ - ⧭ - Black Circle with Down Arrow
  223. 🞄 - 🞄 - Black Slightly Small Circle
  224. • - • - Bullet
  225. ∙ - ∙ - Bullet Operator
  226. ⋅ - ⋅ - Dot Operator
  227. 🌑 - 🌑 - New Moon Symbol
  228. */
  229. // _______ _ __ __
  230. // / ___/ / (_) /__/ /
  231. // / /__/ _ \/ / / _ /
  232. // \___/_//_/_/_/\_,_/
  233. var _Child = {
  234. // oninit(vn){},
  235. // onbeforeupdate(vn, old){},
  236. view(vn){
  237. return [
  238. !_dbs.active_type_filter || _dbs.active_type_filter == vn.attrs.dottype
  239. ? m(_Dot, vn.attrs)
  240. : null,
  241. // add children
  242. typeof vn.attrs.childs !== 'undefined'
  243. ? vn.attrs.childs.map(c => {
  244. c.lang = vn.attrs.lang;
  245. c.level = vn.attrs.level + 1;
  246. return m(_Child, c);
  247. })
  248. : null
  249. ];
  250. }
  251. };
  252. // ______
  253. // / ____/___ ____ ____ ________
  254. // / __/ / __ \/ __ \/ __ \/ ___/ _ \
  255. // / /___/ / / / /_/ / / / / /__/ __/
  256. // /_____/_/ /_/\____/_/ /_/\___/\___/
  257. var _Enonce = {
  258. // oninit(vn){},
  259. // onbeforeupdate(vn, old) {},
  260. view(vn){
  261. vn.attrs.level = 0;
  262. return [
  263. !_dbs.active_type_filter || _dbs.active_type_filter == vn.attrs.dottype
  264. // create dot
  265. ? m(_Dot, vn.attrs)
  266. : null,
  267. // add children
  268. vn.attrs.childs.map(c => {
  269. c.lang = vn.attrs.lang;
  270. c.level = 1;
  271. return m(_Child, c);
  272. })
  273. ]
  274. }
  275. }
  276. // ____ __
  277. // / __ \____ ______/ /_
  278. // / /_/ / __ `/ ___/ __/
  279. // / ____/ /_/ / / / /_
  280. // /_/ \__,_/_/ \__/
  281. var _Part = {
  282. oninit(vn){
  283. this.id = vn.attrs.id;
  284. this.title = vn.attrs.title || "";
  285. },
  286. onbeforeupdate(vn, old){
  287. this.title = vn.attrs.title || "";
  288. },
  289. view(vn){
  290. return m("section", {
  291. 'id' :this.id,
  292. 'class' :'part'
  293. },
  294. [
  295. // create title node
  296. m("h1", {'class':'part-title', 'part':this.id}, m.trust(markdown.renderInline(this.title))),
  297. // create text node
  298. vn.attrs.enonces.map(e => {
  299. // console.log(e.text);
  300. e.lang = vn.attrs.lang;
  301. switch (e.type) {
  302. case "title":
  303. // if(_dbs.active_type_filter){
  304. // console.log('filter:', _dbs.active_type_filter, 'title:',e.title);
  305. // }
  306. // handle titles
  307. return !_dbs.active_type_filter
  308. ? m("h2", {'class':'title'}, m.trust(markdown.renderInline(e.title)))
  309. : null;
  310. break;
  311. case "filet":
  312. // handle filets
  313. return m("h4", {'class':'filet'}, m.trust(markdown.renderInline(e.title)));
  314. break;
  315. default:
  316. // or build structure
  317. return m(_Enonce, Object.assign({"partid":this.id},e));
  318. }
  319. })
  320. ]
  321. )
  322. }
  323. }
  324. // ____ __
  325. // / _/___ / /__________
  326. // / // __ \/ __/ ___/ __ \
  327. // _/ // / / / /_/ / / /_/ /
  328. // /___/_/ /_/\__/_/ \____/
  329. var _Intro = {
  330. oninit(vn){
  331. console.log('_Intro : oninit : vn', vn);
  332. this.id = vn.attrs.id;
  333. this.text = vn.attrs.text || '';
  334. },
  335. onbeforeupdate(vn, old){
  336. this.id = vn.attrs.id;
  337. this.text = vn.attrs.text || '';
  338. },
  339. view(vn){
  340. return m("section", {'class':'intro'}, m("p",m.trust(markdown.renderInline(this.text))));
  341. }
  342. }
  343. // ______ __ _
  344. // / ____/___ ____ ____ ___ _____/ /_(_)___ ____ _____
  345. // / / / __ \/ __ \/ __ \/ _ \/ ___/ __/ / __ \/ __ \/ ___/
  346. // / /___/ /_/ / / / / / / / __/ /__/ /_/ / /_/ / / / (__ )
  347. // \____/\____/_/ /_/_/ /_/\___/\___/\__/_/\____/_/ /_/____/
  348. module.exports = {
  349. oncreate(vn){
  350. document.body.classList.add('mode-connections');
  351. _Ui.init();
  352. },
  353. onbeforeupdate(vn, old){
  354. console.log('Connection, onbeforeupdate old',old, 'vn',vn);
  355. },
  356. view(vn){
  357. // console.log('_ModeConnections view', vn.attrs.lang);
  358. console.log('_dbs.active_type_filter : ', _dbs.active_type_filter);
  359. return m('main', {id:"content", 'class':'mode-connections'}, _dbs.data[vn.attrs.lang].map(p => {
  360. p.lang = vn.attrs.lang;
  361. if(p.id == 'intro'){
  362. return m(_Intro,p);
  363. }else{
  364. return m(_Part,p);
  365. }
  366. })
  367. );
  368. }
  369. }