aboutsummaryrefslogtreecommitdiff
path: root/generator/postrenderer.js
diff options
context:
space:
mode:
Diffstat (limited to 'generator/postrenderer.js')
-rw-r--r--generator/postrenderer.js161
1 files changed, 161 insertions, 0 deletions
diff --git a/generator/postrenderer.js b/generator/postrenderer.js
new file mode 100644
index 0000000..729c4df
--- /dev/null
+++ b/generator/postrenderer.js
@@ -0,0 +1,161 @@
+module.exports={
+ render:function(inf,outf,np,pp){return _render(inf,outf,np,pp);},
+ set_template:function(tmplf){return _set_template(tmplf);}
+};
+const fs=require('fs');
+const jsdom=require('jsdom');
+const path=require('path');
+const aes=require('aes-js');
+const scrypt=require('scrypt-js');
+const btoa=require('btoa');
+const sha256=require('./sha256').sha256;
+const spawn=require('child_process').spawn;
+let template_file='';
+let tmplcont='';
+let tocid;
+let headerlist;
+
+function _dfs(doc,el,le,p)
+{
+ var e=doc.createElement('li');
+ e.innerHTML=`<a class="toctarg" href="#tocanch${tocid}">${el.innerHTML}</a>`;
+ le.appendChild(e);
+ el.id='tocanch'+(tocid++);
+ el.classList.add('tvis');
+ var che=null,i;
+ for(i=p+1;i<headerlist.length;)
+ {
+ if(headerlist[i].tagName<=el.tagName)break;
+ if(headerlist[i].classList.contains('notoc'))continue;
+ if(che===null)
+ {
+ var te=doc.createElement('li');
+ che=doc.createElement('ul');
+ che.classList.add('tocnode');
+ te.appendChild(che);
+ le.appendChild(te);
+ }
+ i=_dfs(doc,headerlist[i],che,i);
+ }
+ return i;
+}
+function footnoter(doc)
+{
+ var footnotes=doc.body.getElementsByTagName("footnote");
+ let starting=doc.getElementById("notediv").children.length;
+ for(var i=0;i<footnotes.length;++i)
+ {
+ var s=footnotes[i].innerHTML;
+ footnotes[i].innerHTML="";
+ var a=doc.createElement("a");
+ a.setAttribute("id","n"+(starting+i+1));
+ a.setAttribute("href","#note"+(starting+i+1));
+ a.setAttribute("class","note");
+ a.innerHTML="["+(starting+i+1)+"]";
+ footnotes[i].parentNode.insertBefore(a,footnotes[i]);
+ var span=doc.createElement("span");
+ span.setAttribute("class","TText");
+ span.innerHTML="<a id=\"note"+(starting+i+1)+"\" href=\"#n"+(starting+i+1)+"\">["+(starting+i+1)+"]</a>: "+s+"<br>";
+ doc.getElementById("notediv").appendChild(span);
+ }
+ starting+=footnotes.length;
+ while(footnotes.length)footnotes[0].remove();
+}
+async function encrypt(doc)
+{
+ let enid=0;
+ for(let i of doc.querySelectorAll('encrypted'))
+ {
+ const key=i.getAttribute('key');
+ i.removeAttribute('key');
+ const contu8=aes.utils.utf8.toBytes(i.innerHTML);
+ const conths=sha256.hash(aes.utils.hex.fromBytes(contu8),{msgFormat:'hex-bytes'});
+ const keyu8=aes.utils.utf8.toBytes(key);
+ const saltu8=aes.utils.utf8.toBytes('hellwhymustiaddsalttothiscrap');
+ const enckey=await new Promise(
+ (resolv,rej)=>
+ {scrypt(keyu8,saltu8,1024,16,2,32,(e,p,k)=>{e?rej(e):k?resolv(k):undefined;});}
+ );
+ const ctr=new aes.ModeOfOperation.ctr(enckey);
+ const enccont=ctr.encrypt(contu8);
+ let encconts='';for(let i=0;i<enccont.length;++i)encconts+=String.fromCharCode(enccont[i]);
+ encconts=btoa(encconts);
+ i.setAttribute('hash',conths);
+ i.setAttribute('encont',encconts);
+ i.setAttribute('enid',enid);
+ i.innerHTML=
+`This section is encrypted. Click <a href="javascript:void(0)" onclick="decryptui(${enid})">here</a>
+to decrypt. <noscript>Note that you need JavaScript enabled for decryption.</noscript>`;
+ ++enid;
+ }
+}
+function _set_template(tmplf)
+{
+ template_file=tmplf;
+ tmplcont=fs.readFileSync(template_file,'utf8');
+}
+async function _render(inf,outf,np,pp)
+{
+ const postcont=fs.readFileSync(inf,'utf8');
+ const tr=new jsdom.JSDOM(tmplcont);
+ const trd=tr.window.document;
+ const cont=fs.readFileSync(inf,'utf8');
+ const contsplit=cont.split('\n');
+ const meta=contsplit.splice(0,4);
+ const preproc=meta[3].trim();
+ trd.getElementById('title').innerHTML=
+ trd.getElementById('titleh').innerHTML=meta[0].trim();
+ trd.getElementById('datetags').innerHTML=`${meta[1].trim()}<br>#${meta[2].split(',').join(' #')}`;
+ if(preproc.length)
+ {
+ const ppargs=preproc.split(' ');
+ const ppcmd=ppargs.splice(0,1);
+ const pp=spawn(ppcmd[0],ppargs,{maxBuffer:1048576});
+ let out='';
+ pp.stdout.setEncoding('utf8');
+ pp.stdout.on('data',(d)=>{out+=d;});
+ pp.stdin.write(contsplit.join('\n'),'utf8');
+ const ppp=new Promise(
+ (resolv,rej)=>
+ {
+ pp.on('close',(r)=>{if(r)rej(r);resolv(out);});
+ }
+ );
+ pp.stdin.end();
+ trd.getElementById('article').innerHTML=await ppp;
+ }
+ else
+ trd.getElementById('article').innerHTML=contsplit.join('\n');
+
+ //Encryption
+ await encrypt(trd);
+
+ //TOC
+ const l=trd.getElementById('article').querySelectorAll('h2,h3,h4,h5,h6');
+ const tocroot=trd.getElementById('tocroot');
+ tocid=0;
+ headerlist=[];
+ for(let i of l)
+ if(!i.classList.contains('notoc'))headerlist.push(i);
+ for(let i=0;i<headerlist.length;)i=_dfs(trd,headerlist[i],tocroot,i);
+ if(!tocroot.children.length)trd.getElementById('tocouter').style.display='none';
+
+ //Footnotes
+ footnoter(trd);
+
+ //Tag list
+ const tgs=meta[2].split(',');
+ for(let i=0;i<tgs.length;++i)
+ {
+ let l=trd.createElement('li');
+ l.innerHTML=`<a href="/blog/list/${tgs[i]}/">${tgs[i]}</a>`;
+ trd.getElementById('tagslist').appendChild(l);
+ }
+
+ //neighboring posts
+ if(pp)trd.getElementById('prevp').href=`${pp}.html`;
+ if(np)trd.getElementById('nextp').href=`${np}.html`;
+
+ fs.writeFileSync(outf,trd.documentElement.outerHTML,'utf8');
+ return outf;
+}