main.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /**
  2. * @Author: Bachir Soussi Chiadmi <bach>
  3. * @Date: 16-04-2017
  4. * @Email: bachir@figureslibres.io
  5. * @Last modified by: bach
  6. * @Last modified time: 18-04-2017
  7. * @License: GPL-V3
  8. */
  9. require('normalize.css/normalize.css');
  10. require('./fonts/amiri/amiri.css');
  11. require('./fonts/dejavu/dejavu.css');
  12. require('./fonts/opensans/opensans.css');
  13. var m = require('mithril');
  14. // var marked = require('marked');
  15. var markdown = require('markdown-it')()
  16. .use(require('markdown-it-footnote'));
  17. var _lang;
  18. var _langs = [
  19. {'lc':'fr', 'label':'fr', 'db':'2-Appuhn-FR-ethicadb.json'},
  20. {'lc':'bra', 'label':'bra', 'db':'ethica-bresilen.json'}
  21. ];
  22. var _dbs = {};
  23. var _dbs_by_id = {};
  24. var _loaded_dbs = 0;
  25. function init(){
  26. // var hash = window.location.hash;
  27. _lang = getUrlVars()['lang'] || 'fr';
  28. console.log(_lang);
  29. // create lang menu
  30. // m.mount(document.getElementById('menus'), _LangMenu);
  31. // load all dbs, when loaded init main app
  32. for (var i = 0; i < _langs.length; i++) {
  33. // if(_langs[i].lc == lang){
  34. // var dbfile = _langs[i].db;
  35. // }
  36. loadJSON(_langs[i].lc, 'assets/jsondb/'+_langs[i].db, onDBLoaded);
  37. }
  38. };
  39. // __ __ ___
  40. // / / ____ _____ ____ _/ |/ /__ ____ __ __
  41. // / / / __ `/ __ \/ __ `/ /|_/ / _ \/ __ \/ / / /
  42. // / /___/ /_/ / / / / /_/ / / / / __/ / / / /_/ /
  43. // /_____/\__,_/_/ /_/\__, /_/ /_/\___/_/ /_/\__,_/
  44. // /____/
  45. var _LangMenu = {
  46. view: function(){
  47. // return m('main', {id:"content"}, DataItems.map(c => m(_Item,c)));
  48. // create ul dom
  49. return m('ul', {id:"languages"}, _langs.map(function(lang){
  50. // create li dom for each lank link
  51. return m('li',
  52. // create a dom
  53. m('a', {
  54. 'lang':lang.lc,
  55. 'href':'/?lang='+lang.lc,
  56. onclick:function(e){
  57. e.preventDefault();
  58. // console.log('click lang', e);
  59. var lang = e.target.getAttribute('lang');
  60. console.log(lang);
  61. if(lang != _lang){
  62. // change url variable
  63. // change db
  64. _lang = lang;
  65. // redraw UI
  66. // m.redraw();
  67. }
  68. return false;
  69. }
  70. }, lang.label)
  71. );
  72. })
  73. );
  74. }
  75. }
  76. // _
  77. // (_)________ ____
  78. // / / ___/ __ \/ __ \
  79. // / (__ ) /_/ / / / /
  80. // __/ /____/\____/_/ /_/
  81. // /___/
  82. function loadJSON(lc, file, callback) {
  83. var xobj = new XMLHttpRequest();
  84. xobj.overrideMimeType("application/json");
  85. // xobj.setRequestHeader('Accept-Encoding', 'gzip');
  86. xobj.open('GET', file, true); // Replace 'my_data' with the path to your file
  87. // xobj.onload = callback;
  88. xobj.onreadystatechange = function () {
  89. // console.log(xobj);
  90. if (xobj.readyState == 4 && xobj.status == "200") {
  91. // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
  92. callback(lc, xobj.responseText);
  93. }
  94. };
  95. xobj.send(null);
  96. // TODO: load and unzip gziped json
  97. // TODO: load multiple languages jsons
  98. };
  99. function onDBLoaded(lc, json){
  100. _dbs[lc] = JSON.parse(json);
  101. _loaded_dbs ++;
  102. if (_loaded_dbs == _langs.length) {
  103. console.log("_dbs", _dbs);
  104. parseDBs();
  105. // m.mount(document.getElementById('app'), _Tree);
  106. m.mount(document.body, _App);
  107. }
  108. }
  109. function parseDBs(){
  110. for(l in _dbs){
  111. // console.log('l', l);
  112. _dbs_by_id[l] = {};
  113. for (p in _dbs[l]) {
  114. // console.log(_dbs[l][p]);
  115. for (e in _dbs[l][p].enonces) {
  116. // console.log('e',e);
  117. _dbs_by_id[l][_dbs[l][p].enonces[e].id] = _dbs[l][p].enonces[e];
  118. for (c in _dbs[l][p][e]){
  119. // console.log(_db[p][e][c]);
  120. _dbs_by_id[_dbs[l][p][e][c].id] = _dbs[l][p][e][c];
  121. }
  122. }
  123. }
  124. }
  125. console.log('_dbs_by_id', _dbs_by_id);
  126. }
  127. // __ _ __
  128. // / / (_)___ / /__
  129. // / / / / __ \/ //_/
  130. // / /___/ / / / / ,<
  131. // /_____/_/_/ /_/_/|_|
  132. var _Link = {
  133. targetid:"",
  134. opened:false,
  135. oninit: function(vn){
  136. // console.log("INIT LINK : vn", vn);
  137. // define target id
  138. vn.state.tid = vn.attrs.href;
  139. },
  140. onupdate: function(vn){
  141. vn.state.tid = vn.attrs.href;
  142. },
  143. view: function(vn){
  144. if(vn.state.opened){
  145. // console.log('vn.state.tid', vn.state);
  146. return m('div', {'class':'opened-link'},
  147. [
  148. m('span', {'class':"link text"}, vn.children),
  149. typeof _dbs_by_id[_lang][vn.state.tid].childs != "undefined"
  150. ? m(_Enonce, _dbs_by_id[_lang][vn.state.tid])
  151. : m(_Item, _dbs_by_id[_lang][vn.state.tid])
  152. ]
  153. );
  154. }else{
  155. // console.log(vn);
  156. return m('a', {
  157. 'class':'link',
  158. 'href':'#'+vn.state.tid,
  159. 'rel':vn.state.tid,
  160. onclick:function(e){
  161. e.preventDefault();
  162. console.log('click', vn);
  163. vn.state.opened = true;
  164. return false;
  165. }
  166. }, vn.children);
  167. }
  168. }
  169. }
  170. // ______ __
  171. // /_ __/__ _ __/ /_
  172. // / / / _ \| |/_/ __/
  173. // / / / __/> </ /_
  174. // /_/ \___/_/|_|\__/
  175. // recusive function to record information of all subnodes
  176. function parseTextDom(nodes){
  177. var list = [];
  178. // loop through childNodes
  179. for (var i = 0; i < nodes.length; i++) {
  180. var n = {};
  181. if(typeof nodes[i].localName != "undefined"){
  182. n.tag=nodes[i].localName;
  183. if (n.tag == 'p') {
  184. // replace p by div as we will insert other div in them
  185. n.tag = 'div';
  186. n.attrs = {'class':'paragraph'};
  187. }
  188. if (n.tag == 'a') {
  189. // record the href attribute for cross reference
  190. n.attrs = {'href':nodes[i].attributes.href.value};
  191. }
  192. if(nodes[i].childNodes.length){
  193. // again parse node's childs
  194. n.childs = parseTextDom(nodes[i].childNodes);
  195. }
  196. }else if (nodes[i].textContent.length > 1){
  197. // if node has no localName it is probably a #text node
  198. // we record it if it's not empty
  199. n.tag='#text';
  200. n.text=nodes[i].textContent;
  201. }
  202. // add the node to the list if it has a tag
  203. if(typeof n.tag != "undefined")
  204. list.push(n);
  205. }
  206. return list;
  207. }
  208. // recusive fucntion to generate mithril object from information recorded with parseTextDom()
  209. function populateTextDom(n,i){
  210. // console.log('populateTextDom : '+i,n);
  211. return n.tag == "#text"
  212. ? m.trust(n.text)
  213. : m(
  214. n.tag != 'a' ? n.tag : _Link,
  215. typeof n.attrs != "undefined" ? n.attrs : {},
  216. typeof n.childs != "undefined"
  217. ? n.childs.map(populateTextDom)
  218. : typeof n.text != "undefined"
  219. ? m.trust(n.text)
  220. : null
  221. );
  222. }
  223. var _Text = {
  224. id:null,
  225. text:"",
  226. texthtml:"",
  227. textdom:null,
  228. textchilds:[],
  229. parsetext: function(){
  230. // console.log('parsetext', this);
  231. // !! we need to convert markdown to html here because parseTextDom() is recursive through nodes tree
  232. // convert markdown to html
  233. this.texthtml = markdown.render(this.text)
  234. // TODO: fixe number link text disapear [3](1d3) ( in 104d )
  235. // TODO: fixe parenthèse disparait _(par les Défin. [test 3](1d3) et [test 5](1d5))_ ( in 104d )
  236. // parse html string to virtual dom
  237. this.textdom = new DOMParser().parseFromString(this.texthtml, "text/html");
  238. // get the text nodes (avoid html document extra)
  239. this.textchilds = parseTextDom(this.textdom.getElementsByTagName('body')[0].childNodes);
  240. },
  241. oninit: function(vn){
  242. this.id = vn.attrs.id;
  243. this.text = vn.attrs.text;
  244. this.parsetext();
  245. },
  246. onbeforeupdate: function(vn,old){
  247. this.text = vn.attrs.text;
  248. this.parsetext();
  249. },
  250. view: function(vn){
  251. // console.log('_Text :: view : '+vn.attrs.slug, vn);
  252. return m('div',
  253. {'class':'text'},
  254. // loop through childNodes list generated by parseTextDom() in init
  255. this.textchilds.map(populateTextDom)
  256. ); // /m.div.text
  257. } // view:
  258. }
  259. // ______
  260. // / _/ /____ ____ ___
  261. // / // __/ _ \/ __ `__ \
  262. // _/ // /_/ __/ / / / / /
  263. // /___/\__/\___/_/ /_/ /_/
  264. var _Item = {
  265. id:null,
  266. part:null,
  267. type:null,
  268. nested:false,
  269. oninit: function(vn){
  270. // console.log('vn.attrs', vn.attrs);
  271. this.id = vn.attrs.id;
  272. this.type = vn.attrs.type;
  273. // vn.state.part = vn.state.slug.match(/^(\d)(.+)/)[1];
  274. this.text = vn.attrs.text;
  275. this.nested = vn.attrs.nested || false;
  276. },
  277. onbeforeupdate: function(vn, old){
  278. this.nested = vn.attrs.nested || false;
  279. this.type = vn.attrs.type;
  280. this.text = vn.attrs.text;
  281. },
  282. view: function(vn){
  283. return m("section", {
  284. 'id':this.id,
  285. 'class':'item'+(this.nested ? ' nested':'')
  286. },
  287. [
  288. // create title node
  289. m("h3", {
  290. // 'ref':vn.attrs.href,
  291. onclick: function(e){
  292. vn.state.active = vn.state.active ? 0 : 1;
  293. }
  294. }, this.type),
  295. // create text node
  296. m(_Text, {'text':this.text, 'id':this.id})
  297. ]
  298. )
  299. }
  300. };
  301. // ______
  302. // / ____/___ ____ ____ ________
  303. // / __/ / __ \/ __ \/ __ \/ ___/ _ \
  304. // / /___/ / / / /_/ / / / / /__/ __/
  305. // /_____/_/ /_/\____/_/ /_/\___/\___/
  306. var _Enonce = {
  307. partid:null,
  308. id:null,
  309. title:null,
  310. text:null,
  311. nested:false,
  312. childs:[],
  313. oninit:function(vn){
  314. // // console.log('Enonce on init', vn);
  315. this.partid = vn.attrs.partid;
  316. this.id = vn.attrs.id;
  317. this.title = vn.attrs.title;
  318. this.text = vn.attrs.text;
  319. this.childs = vn.attrs.childs;
  320. this.nested = vn.attrs.nested || false;
  321. },
  322. onbeforeupdate:function(vn, old) {
  323. // console.log(vn.attrs.childs);
  324. this.title = vn.attrs.title;
  325. this.text = vn.attrs.text;
  326. this.childs = vn.attrs.childs;
  327. this.nested = vn.attrs.nested || false;
  328. // if(vn.attrs.id == '1d1') console.log('_Enonce UPDATE, text :', vn.attrs.text);
  329. },
  330. view: function(vn){
  331. // if(vn.attrs.id == '1d1') console.log('_Enonce VIEW, text :', vn.attrs.text);
  332. return m("section", {
  333. 'id' :this.id,
  334. 'class' :'enonce'+(this.nested ? ' nested':'')
  335. },
  336. [
  337. // create title node
  338. m("h2", {}, this.title),
  339. // create text node
  340. m(_Text, {'text':this.text, 'id':this.id}),
  341. // addd children
  342. this.childs.map(function(c){
  343. return m(_Item, c)
  344. })
  345. ])
  346. }
  347. }
  348. // ____ __
  349. // / __ \____ ______/ /_
  350. // / /_/ / __ `/ ___/ __/
  351. // / ____/ /_/ / / / /_
  352. // /_/ \__,_/_/ \__/
  353. var _Part = {
  354. oninit: function(vn){
  355. this.id = vn.attrs.id;
  356. this.title = vn.attrs.title;
  357. this.enonces = vn.attrs.enonces;
  358. },
  359. onbeforeupdate: function(vn, old){
  360. // console.log('_Part, onbeforeupdate old',old);
  361. this.title = vn.attrs.title;
  362. this.enonces = vn.attrs.enonces;
  363. },
  364. view: function(vn){
  365. // console.log(vn.attrs.enonces);
  366. return m("section", {
  367. 'id' :this.id,
  368. 'class' :'part'
  369. },
  370. [
  371. // create title node
  372. m("h1", {'class':'part'}, this.title),
  373. // create text node
  374. this.enonces.map(function(e){
  375. // console.log(e.text);
  376. return m(_Enonce, Object.assign({"partid":this.id},e))
  377. })
  378. ]
  379. )
  380. }
  381. }
  382. // ______
  383. // /_ __/_______ ___
  384. // / / / ___/ _ \/ _ \
  385. // / / / / / __/ __/
  386. // /_/ /_/ \___/\___/
  387. var _Tree = {
  388. view: function(){
  389. console.log('_Tree view', _lang);
  390. return m('main', {id:"content"}, _dbs[_lang].map(function(p){
  391. // console.log("MAP _dbs", p);
  392. return m(_Part,p);
  393. })
  394. );
  395. }
  396. }
  397. // ___
  398. // / | ____ ____
  399. // / /| | / __ \/ __ \
  400. // / ___ |/ /_/ / /_/ /
  401. // /_/ |_/ .___/ .___/
  402. // /_/ /_/
  403. var _App = {
  404. view: function(){
  405. console.log('_App view', _lang);
  406. return [
  407. m('header', [
  408. m('h1', 'Ethica'),
  409. m('aside', {'id':"menus"}, m(_LangMenu) )
  410. ]),
  411. m(_Tree),
  412. m('footer', [
  413. m('p', m.trust('© 2017 <a href="./">Ethica Spinoza</a>'))
  414. ])
  415. ]
  416. }
  417. }
  418. // __ __ __
  419. // / / / /__ / /___ ___ __________
  420. // / /_/ / _ \/ / __ \/ _ \/ ___/ ___/
  421. // / __ / __/ / /_/ / __/ / (__ )
  422. // /_/ /_/\___/_/ .___/\___/_/ /____/
  423. // /_/
  424. function getUrlVars() {
  425. var vars = {};
  426. var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
  427. vars[key] = value;
  428. });
  429. return vars;
  430. }
  431. // _ _ __
  432. // (_)___ (_) /_
  433. // / / __ \/ / __/
  434. // / / / / / / /_
  435. // /_/_/ /_/_/\__/
  436. init()