editor.js 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  1. /*jslint browser: true*/
  2. "use strict";
  3. /*jshint esversion: 6 */
  4. var visual_editor = "";
  5. var code_editor = "";
  6. var is_visual_editor = true;
  7. var is_menu_open = false;
  8. var is_bookmark_aside_shown = false;
  9. var has_line_numbering = false;
  10. var is_collab = false;
  11. var is_mathjax = false;
  12. var header = "";
  13. var footer = "";
  14. var url_canonical = "https://freeshell.de/alkeon/api/upload.php";
  15. var visual_editor = true;
  16. var template_id = 0;
  17. var DEBUG = false;
  18. const mathjax_library = 'js/mathjax.js';
  19. var array_b64_images = [];
  20. function reload_mathjax(){
  21. if(is_mathjax){
  22. MathJax = {
  23. tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]}
  24. };
  25. let script = document.createElement('script');
  26. script.src = mathjax_library;
  27. document.head.appendChild(script);
  28. }
  29. }
  30. function remove_mathjax() {
  31. if(MathJax.startup != null){
  32. let jax = MathJax.startup.document.getMathItemsWithin(document.body);
  33. for (var i = 0, m = jax.length; i < m; i++) {
  34. let tex = "$" + jax[i].math + "$";
  35. let root = jax[i].typesetRoot;
  36. let render_parent = jax[i].typesetRoot.parentElement
  37. render_parent.insertBefore(document.createTextNode(tex),root);
  38. render_parent.removeChild(root);
  39. }
  40. }
  41. }
  42. function change_input() {
  43. const header = document.getElementsByTagName("H1")[0];
  44. if(header != null){
  45. document.getElementById('title').innerText = header.innerText;
  46. }
  47. }
  48. function set_loading_file_popup_visibility(is_visible) {
  49. if(is_visible)
  50. document.getElementById('loading-file-popup').style.display = 'block';
  51. else
  52. document.getElementById('loading-file-popup').style.display = 'none';
  53. }
  54. function startEditors() {
  55. document.body.ondrop = function(e){
  56. e.preventDefault();
  57. drop(e);
  58. };
  59. let element_visual = document.getElementById("visual-editor");
  60. if(element_visual !== null) {
  61. start_visual_editor(element_visual);
  62. }
  63. let element = document.getElementById("code-editor");
  64. if(element !== null) {
  65. start_code_editor(element);
  66. }
  67. document.getElementById("file").addEventListener('change', function (event) {
  68. let input = document.querySelector("#file");
  69. let file = input.files[0];
  70. load_file(file);
  71. input.value = null;
  72. });
  73. let focusable_div = element_visual.querySelector('.visual-editor > div');
  74. setTimeout(function() {
  75. focusable_div.focus();
  76. }, 0);
  77. }
  78. function start_visual_editor(element){
  79. let options = {
  80. "clear_button": true,
  81. "link": true,
  82. "heading": true,
  83. "list": true,
  84. "table": true,
  85. "image": true,
  86. "block": true,
  87. "code": true,
  88. "embed": true,
  89. "save": true,
  90. "load": true,
  91. "undo": true,
  92. "redo": true
  93. };
  94. visual_editor = new creta(1, element, options);
  95. let div = document.createElement("div");
  96. let save_toolbar = element.querySelector('.save_toolbar');
  97. save_toolbar.onclick = function(){save();};
  98. let template_button = document.querySelector('.accept-template');
  99. template_button.onclick = function(){set_template_id(4);};
  100. let autoload_button = document.querySelector('.accept-autoload');
  101. autoload_button.onclick = function(){
  102. accepted_autoload();
  103. this.parentElement.style.display = 'none';
  104. };
  105. div.innerHTML = `<div class="button left pdf" onclick="editor2pdf()">
  106. <div class="tooltip">
  107. <img width=24 height=24 src="icons/pdf.svg" alt="Convert to PDF icon">
  108. <div class="tooltiptext">Convert to PDF by sending text to server.</div>
  109. </div>
  110. </div>
  111. <div class="button left disabled pdf-disabled" style="display:none;">
  112. <div class="tooltip">
  113. <img width=24 height=24 src="icons/pdf.svg" alt="Convert to PDF icon">
  114. <div class="tooltiptext">Convert to PDF by sending text to server.</div>
  115. </div>
  116. </div>
  117. <div class="button left close_pdf" onclick="close_pdf_viewer()" style="display:none;">
  118. <div class="tooltip">
  119. <img width=24 height=24 src="icons/close_pdf.svg" alt="Close PDF tab">
  120. <div class="tooltiptext">Close PDF tab.</div>
  121. </div>
  122. </div>
  123. <div class="button left" onclick="download_file()">
  124. <div class="tooltip">
  125. <img src="icons/download.svg" alt="Download savestate icon">
  126. <div class="tooltiptext">Download document to file</div>
  127. </div>
  128. </div>
  129. <div class="button left">
  130. <div class="tooltip">
  131. <input type="file" style="display:none;" id="file">
  132. <label for="file" class="btn command"><img src="icons/upload.svg" alt="Upload savestate icon"></label>
  133. <div class="tooltiptext">Upload document to file</div>
  134. </div>
  135. </div>
  136. <div class="button right btn command tjs" onclick="start_togetherjs()" style="display:none;">
  137. <div class="tooltip">
  138. <img width=24 height=24 src="icons/collab.svg" alt="Collaborate">
  139. </div>
  140. </div>
  141. <div class="change-editor right tooltip">
  142. <input class="checkbox_change_editor" type="checkbox" onclick="changeEditor()">
  143. <div class="checkbox-text"><img width=24 height=24 alt="code editor" src="icons/code.svg"></div>
  144. <div class="tooltiptext">Convert between languages</div>
  145. </div>`;
  146. visual_editor.add_ui_element(element, div);
  147. div.appendChild(get_error_popup_div());
  148. visual_editor.add_ui_element(element, div);
  149. }
  150. function get_error_popup_div(){
  151. let popup = document.createElement("div");
  152. popup.className = 'popup block_popup';
  153. popup.style = "display:none;";
  154. popup.id = "error-ui";
  155. let popup_text = document.createElement("div");
  156. popup_text.id = 'text_error';
  157. let close_button_div = document.createElement("div");
  158. close_button_div.className = 'close_button';
  159. close_button_div.onclick = function(){
  160. this.parentElement.style.display = 'none';
  161. };
  162. close_button_div.appendChild(document.createTextNode("🗙"));
  163. popup.appendChild(document.createElement('br'));
  164. popup.appendChild(popup_text);
  165. popup.appendChild(close_button_div);
  166. return popup;
  167. }
  168. function start_code_editor(element){
  169. let options = {
  170. "clear_button": true,
  171. "save": true,
  172. "load": true,
  173. "undo": true,
  174. "redo": true
  175. };
  176. code_editor = new creta(2, element, options);
  177. let div = document.createElement("div");
  178. div.innerHTML = `<div class="button left" onclick="download_file()">
  179. <div class="tooltip">
  180. <img src="icons/download.svg" alt="Download savestate icon">
  181. <div class="tooltiptext">Download document to file</div>
  182. </div>
  183. </div>
  184. <div class="button left">
  185. <div class="tooltip">
  186. <input type="file" style="display:none;" id="file">
  187. <label for="file" class="btn command"><img src="icons/upload.svg" alt="Upload savestate icon"></label>
  188. <div class="tooltiptext">Upload document to file</div>
  189. </div>
  190. </div>
  191. <div class="button right btn command tjs" onclick="start_togetherjs()" style="display:none;">
  192. <div class="tooltip">
  193. <img width=24 height=24 src="icons/collab.svg" alt="Collaborate">
  194. </div>
  195. </div>
  196. <div class="change-editor right tooltip">
  197. <input class="checkbox_change_editor" type="checkbox" onclick="changeEditor()">
  198. <div class="checkbox-text"><img width=24 height=24 alt="code editor" src="icons/code.svg"></div>
  199. <div class="tooltiptext">Convert between languages</div>
  200. </div>`;
  201. code_editor.add_ui_element(element, div);
  202. div.innerHTML += `<div id="error-ui" class="popup overflow-popup" style="display:none;">
  203. <div id="text_error">Write container class</div>
  204. <div class="close_button" onclick="this.parentElement.parentElement.style.display = 'none';">🗙</div>
  205. </div>`;
  206. code_editor.add_ui_element(element, div);
  207. code_editor.change_visibility(element);
  208. }
  209. var activated = false;
  210. function start_togetherjs(){
  211. if(activated){
  212. let tjs = document.getElementsByClassName('tjs');
  213. for(let i = 0; i < tjs.length; ++i){
  214. tjs[i].style.color = 'black';
  215. tjs[i].style.backgroundColor = 'white';
  216. }
  217. activated = false;
  218. }else{
  219. let tjs = document.getElementsByClassName('tjs');
  220. for(let i = 0; i < tjs.length; ++i){
  221. tjs[i].style.color = 'black';
  222. tjs[i].style.backgroundColor = 'white';
  223. }
  224. activated = true;
  225. }
  226. TogetherJS();
  227. return false;
  228. }
  229. function start_menu(){
  230. if(is_menu_open){
  231. document.getElementById('options').style.display = "none";
  232. document.getElementById("editors").classList.remove("limit_width");
  233. document.getElementById('editors').classList.remove("hide-if-mobile");
  234. document.getElementById('bookmarks').classList.remove("hide-if-mobile");
  235. document.getElementById('options').classList.remove("options-width");
  236. is_menu_open = false;
  237. }else{
  238. document.getElementById('options').style.display = "block";
  239. document.getElementById('options').classList.add("options-width");
  240. document.getElementById('editors').classList.add("hide-if-mobile");
  241. document.getElementById('bookmarks').classList.add("hide-if-mobile");
  242. document.getElementById("editors").classList.add("limit_width");
  243. is_menu_open = true;
  244. }
  245. return false;
  246. }
  247. function save(){
  248. try{
  249. if(is_visual_editor)
  250. remove_mathjax();
  251. }catch(e){}
  252. try{
  253. visual_editor.save();
  254. var name = document.getElementById('title');
  255. localStorage.setItem('name', name.innerHTML);
  256. var select_titles = document.getElementById('select-title').checked;
  257. if(select_titles){
  258. select_titles = 1;
  259. }else{
  260. select_titles = 0;
  261. }
  262. localStorage.setItem('select_title', select_titles);
  263. var line_numbers = document.getElementById('line-numbers').checked;
  264. if(line_numbers){
  265. line_numbers = 1;
  266. }else{
  267. line_numbers = 0;
  268. }
  269. localStorage.setItem('line_numbers', line_numbers);
  270. var set_debug_text = document.getElementById('set-debug').checked;
  271. if(set_debug_text){
  272. set_debug_text = 1;
  273. }else{
  274. set_debug_text = 0;
  275. }
  276. localStorage.setItem('is_debug', set_debug_text);
  277. localStorage.setItem('template', template_id);
  278. localStorage.setItem('custom_start', document.querySelector('.start').value);
  279. localStorage.setItem('custom_end', document.querySelector('.end').value);
  280. localStorage.setItem('tjs', document.getElementById('set-collab').checked);
  281. localStorage.setItem('mathjax', document.getElementById('set-mathjax').checked);
  282. }catch(e){
  283. console.log("Couldn't save history " + e);
  284. }
  285. if(is_visual_editor)
  286. reload_mathjax();
  287. }
  288. var autoSave = window.setInterval(function(){
  289. save();
  290. change_input();
  291. if(is_bookmark_aside_shown){
  292. if(is_visual_editor){
  293. set_bookmarks(document.querySelector("#visual-editor").querySelector(".visual-editor").innerHTML);
  294. }else{
  295. set_bookmarks(document.querySelector("#code-editor").querySelector(".visual-editor").innerHTML);
  296. }
  297. }
  298. visual_editor.save();
  299. }, 6000 * 5);
  300. window.onbeforeprint = function(){
  301. save();
  302. //Print PDF from HTML browser if there isn't API server
  303. //Hide UX elements
  304. let nav = document.getElementsByTagName("nav")[0];
  305. let toolbar = document.getElementById("visual-editor").querySelector(".edit-controls");
  306. let options = document.getElementById("options");
  307. let bookmarks = document.getElementById("bookmarks");
  308. bookmarks.style.display = "none";
  309. options.style.display = "none";
  310. nav.style.display = "none";
  311. toolbar.style.display = "none";
  312. //Free viewport, this solves issues with one page only documents
  313. let main = document.getElementsByTagName("main")[0];
  314. main.removeAttribute('id');
  315. //Hide images and tables delete buttons
  316. let delete_buttons = document.querySelectorAll(".deletebutton");
  317. for (let element of delete_buttons) {
  318. element.style.display = "none";
  319. }
  320. };
  321. window.onafterprint = function(){
  322. //Show UX elements
  323. let pdf_icon = visual_editor.element.querySelector('.pdf');
  324. pdf_icon.style.display = "flex";
  325. let pdf_disabled_icon = visual_editor.element.querySelector('.pdf-disabled');
  326. pdf_disabled_icon.style.display = "none";
  327. let toolbar = document.getElementById("visual-editor").querySelector(".edit-controls");
  328. let nav = document.getElementsByTagName("nav")[0];
  329. nav.style.display = "block";
  330. toolbar.style.display = "block";
  331. //Limit viewport to screen size
  332. let main = document.getElementsByTagName("main")[0];
  333. main.id = "viewport";
  334. //Show images and tables delete buttons
  335. let delete_buttons = document.querySelectorAll(".deletebutton");
  336. for (let element of delete_buttons) {
  337. element.style.display = "";
  338. }
  339. };
  340. function load(){
  341. visual_editor.load();
  342. try{
  343. if(localStorage.getItem("line-numbers") != null){
  344. if(localStorage.getItem("line-numbers") == true){
  345. document.getElementById('line-numbers').click();
  346. }
  347. }
  348. if(localStorage.getItem("select-title") != null){
  349. if(localStorage.getItem("select-title") == true){
  350. document.getElementById('select-title').click();
  351. }
  352. }
  353. if(localStorage.getItem("name") != null){
  354. document.getElementById('title').innerHTML = localStorage.getItem("name");
  355. }
  356. if(localStorage.getItem("is-debug") != null){
  357. if(localStorage.getItem("is-debug") == true){
  358. document.getElementById('set-debug').click();
  359. }
  360. }
  361. if(localStorage.getItem("custom-start") != null){
  362. document.querySelector('.start').innerHTML = localStorage.getItem("custom-start");
  363. }
  364. if(localStorage.getItem("custom-end") != null){
  365. document.querySelector('.end').innerHTML = localStorage.getItem("custom-end");
  366. }
  367. if(localStorage.getItem("template") != null ){
  368. switch(parseInt(localStorage.getItem("template"))){
  369. case 0: document.getElementById('notes').click();break;
  370. case 1: document.getElementById('thesis').click();break;
  371. case 2: document.getElementById('presentation').click();break;
  372. case 3: document.getElementById('custom').checked = true;break;
  373. case 4: document.getElementById('paper').click();break;
  374. }
  375. }
  376. if(localStorage.getItem("tjs") != null && localStorage.getItem("set-collab") == "true"){
  377. document.getElementById('set-collab').click();
  378. }
  379. if(localStorage.getItem("mathjax") != null && localStorage.getItem("mathjax") == "true"){
  380. document.getElementById('set-mathjax').click();
  381. }
  382. }catch(e){
  383. console.log("Couldn't load history " + e);
  384. }
  385. if(get_param('file')){
  386. document.getElementById('autoload-popup').style.display = 'block';
  387. }
  388. reload_mathjax();
  389. }
  390. function get_param(name){
  391. if(name=(new RegExp('[?&]'+encodeURIComponent(name)+'=([^&]*)')).exec(location.search))
  392. return decodeURIComponent(name[1]);
  393. }
  394. function accepted_autoload(){
  395. const options = {
  396. method: 'GET',
  397. mode: 'cors'
  398. };
  399. fetch(get_param('file'), options).then(response => response.blob())
  400. .then(blob => load_file(blob)).catch((error) => {
  401. fail_found("Autoload files only allowed of same site files");
  402. });
  403. }
  404. function changeEditor(){
  405. if(is_visual_editor){
  406. is_visual_editor = false;
  407. visual_to_code_editor();
  408. document.getElementById('code-editor').style.display = 'flex';
  409. document.getElementById('visual-editor').style.display = 'none';
  410. let all_checkbox = document.getElementsByClassName('checkbox_change_editor');
  411. for(let checkbox_position = 0; checkbox_position < all_checkbox.length; ++checkbox_position){
  412. all_checkbox[checkbox_position].checked = true;
  413. }
  414. }else{
  415. is_visual_editor = true;
  416. code_to_visual_editor();
  417. document.getElementById('code-editor').style.display = 'none';
  418. document.getElementById('visual-editor').style.display = 'flex';
  419. let all_checkbox = document.getElementsByClassName('checkbox_change_editor');
  420. for(let checkbox_position = 0; checkbox_position < all_checkbox.length; ++checkbox_position){
  421. all_checkbox[checkbox_position].checked = false;
  422. }
  423. }
  424. }
  425. function visual_to_code_editor(){
  426. remove_mathjax();
  427. let editor_content = visual_editor.get_text();
  428. log_text("visual editor content " + editor_content);
  429. let h2t = new html2tedi();
  430. editor_content = h2t.convert(editor_content);
  431. log_text("html2tedi " + editor_content);
  432. code_editor.set_text_code(editor_content);
  433. save();
  434. let p = document.querySelector("#bookmarks");
  435. if(is_bookmark_aside_shown){
  436. set_bookmarks(document.querySelector("#code-editor").querySelector(".visual-editor").innerHTML);
  437. p.style.display = "block";
  438. } else {
  439. p.style.display = "none";
  440. }
  441. array_b64_images = visual_editor.get_images_b64();
  442. document.getElementById('set-mathjax').disabled = true;
  443. }
  444. function code_to_visual_editor(){
  445. let editor_content = code_editor.get_text_code();
  446. log_text("code editor content " + editor_content);
  447. let t2h = new tedi2html();
  448. editor_content = t2h.convert(editor_content);
  449. log_text("tedi2html " + editor_content);
  450. visual_editor.set_images_b64(array_b64_images);
  451. visual_editor.set_text(editor_content);
  452. save();
  453. let p = document.getElementById('bookmarks');
  454. if(is_bookmark_aside_shown){
  455. set_bookmarks(document.querySelector("#visual-editor").querySelector(".visual-editor").innerHTML);
  456. p.style.display = "block";
  457. }else{
  458. p.style.display = "none";
  459. }
  460. document.getElementById('set-mathjax').disabled = false;
  461. reload_mathjax();
  462. }
  463. function fail_found(text){
  464. document.getElementById('error-ui').style.display = "block";
  465. document.getElementById('text_error').innerHTML = text;
  466. }
  467. function set_line_numbering(){
  468. if(has_line_numbering){
  469. document.getElementById('enumerate-lines').href = "";
  470. has_line_numbering = false;
  471. } else {
  472. document.getElementById('enumerate-lines').href = "css/enumerate_lines.css";
  473. has_line_numbering = true;
  474. }
  475. return false;
  476. }
  477. function set_debug(){
  478. if(DEBUG){
  479. visual_editor.DEBUG = false;
  480. code_editor.DEBUG = false;
  481. DEBUG = false;
  482. }else{
  483. visual_editor.DEBUG = true;
  484. code_editor.DEBUG = true;
  485. DEBUG = true;
  486. }
  487. return false;
  488. }
  489. function show_template_popup(){
  490. document.getElementById('template-popup').style.display = 'block';
  491. }
  492. function show_bookmarks_aside(){
  493. if(is_bookmark_aside_shown){
  494. is_bookmark_aside_shown = false;
  495. }else{
  496. if(is_visual_editor)
  497. set_bookmarks(document.querySelector("#visual-editor").querySelector(".visual-editor").innerHTML);
  498. else
  499. set_bookmarks(document.querySelector("#code-editor").querySelector(".visual-editor").innerHTML);
  500. is_bookmark_aside_shown = true;
  501. }
  502. let p = document.getElementById('bookmarks');
  503. if(is_bookmark_aside_shown)
  504. p.style.display = "block";
  505. else
  506. p.style.display = "none";
  507. return false;
  508. }
  509. function log_text(line){
  510. if(DEBUG)
  511. console.log(line);
  512. }
  513. function set_template_id(id){
  514. template_id = id;
  515. set_template(id);
  516. }
  517. function set_template(){
  518. if(template_id == 0){
  519. header = `\\documentclass[12pt]{article}
  520. \\usepackage{afterpage}
  521. \\usepackage{ltablex}
  522. \\usepackage{amssymb}
  523. \\usepackage{float}
  524. \\usepackage{amsmath}
  525. \\usepackage{caption}
  526. \\usepackage{array}
  527. \\usepackage{xltabular}
  528. \\usepackage{longtable}
  529. \\usepackage{changepage}
  530. \\usepackage{enumitem}
  531. \\usepackage{booktabs}
  532. \\usepackage{hyperref}
  533. \\hypersetup{
  534. colorlinks=true,
  535. linkcolor=blue,
  536. filecolor=magenta,
  537. urlcolor=blue,
  538. }\n
  539. \\urlstyle{same}
  540. \\newcommand{\\tabitem}{~~\\llap{\\textbullet}~~}
  541. \\usepackage{graphicx}\n
  542. \\DeclareGraphicsExtensions{.eps, .jpg, .png, .jpeg}
  543. \\begin{document}`;
  544. footer = '\\end{document}';
  545. }else if(template_id == 1){
  546. header = `\\documentclass[11pt,a4paper]{report}\n
  547. \\usepackage[utf8]{inputenc}\n
  548. \\usepackage{hyperref}\n
  549. \\usepackage{verbatim}\n
  550. \\usepackage{graphicx}\n
  551. \\usepackage{underscore}\n
  552. \\usepackage{afterpage}
  553. \\usepackage[spanish]{babel}
  554. \\usepackage{ltablex}
  555. \\usepackage{amssymb}
  556. \\usepackage{float}
  557. \\usepackage{caption}
  558. \\usepackage{array}
  559. \\usepackage{xltabular}
  560. \\usepackage{longtable}
  561. \\usepackage{changepage}
  562. \\usepackage{enumitem}
  563. \\usepackage{booktabs}
  564. \\usepackage{hyperref}
  565. \\hypersetup{
  566. colorlinks=true,
  567. linkcolor=blue,
  568. filecolor=magenta,
  569. urlcolor=blue,
  570. }\n
  571. \\urlstyle{same}\n
  572. \\DeclareGraphicsExtensions{.eps, .jpg, .png, .jpeg}
  573. \\newcommand{\\tabitem}{~~\\llap{\\textbullet}~~}
  574. \\usepackage[protrusion = true,final]{microtype}\n
  575. \\setlength{\\emergencystretch}{10pt}
  576. \n\n
  577. \\title{` + document.getElementById("name").value + "}" +
  578. `\\hypersetup{pageanchor=false}\n
  579. \n\\setlength\\parskip{1em}\n
  580. \\begin{document}\n
  581. \\maketitle\n
  582. \\newpage\n
  583. \\listoffigures\n
  584. \\listoftables
  585. \\thispagestyle{empty}\n
  586. \\tableofcontents\n
  587. \\newpage\n
  588. \\setcounter{page}{1}\n`;
  589. footer = '\\end{document}';
  590. }else if(template_id == 2){
  591. header = `\\documentclass[t]{beamer}
  592. \\usetheme{Madrid}
  593. \\usepackage{afterpage}
  594. \\usepackage{amssymb}
  595. \\usepackage{float}
  596. \\usepackage{array}
  597. \\usepackage{amsmath}
  598. \\usepackage{xltabular}\n
  599. \\usepackage{graphicx}
  600. \\usepackage{longtable}
  601. \\usepackage{changepage}
  602. \\usepackage{enumitem}
  603. \\usepackage{booktabs}
  604. \\usepackage{hyperref}
  605. \\hypersetup{
  606. colorlinks=true,
  607. linkcolor=blue,
  608. filecolor=magenta,
  609. urlcolor=blue,
  610. }\n
  611. \\urlstyle{same}\n
  612. \\DeclareGraphicsExtensions{.eps, .jpg, .png, .jpeg}
  613. \\usepackage{booktabs}
  614. \\usepackage{xpatch}
  615. \\listoffigures
  616. \\title{` + document.getElementById("name").value + "}\\begin{document}\\frame{\\titlepage}";
  617. footer = '\\end{document}';
  618. }else if(template_id == 3){
  619. header = `\\documentclass[11pt,a4paper]{book}\n
  620. \\usepackage[utf8]{inputenc}\n
  621. \\usepackage{hyperref}\n
  622. \\usepackage{verbatim}\n
  623. \\usepackage{graphicx}\n
  624. \\usepackage{underscore}\n
  625. \\usepackage{afterpage}
  626. \\usepackage[spanish]{babel}
  627. \\usepackage{ltablex}
  628. \\usepackage{amssymb}
  629. \\usepackage{float}
  630. \\usepackage{caption}
  631. \\usepackage{array}
  632. \\usepackage{xltabular}
  633. \\usepackage{longtable}
  634. \\usepackage{changepage}
  635. \\usepackage{enumitem}
  636. \\usepackage{booktabs}
  637. \\usepackage{hyperref}
  638. \\hypersetup{
  639. colorlinks=true,
  640. linkcolor=blue,
  641. filecolor=magenta,
  642. urlcolor=blue,
  643. }\n
  644. \\urlstyle{same}\n
  645. \\DeclareGraphicsExtensions{.eps, .jpg, .png, .jpeg}
  646. \\newcommand{\\tabitem}{~~\\llap{\\textbullet}~~}
  647. \\usepackage[protrusion = true,final]{microtype}\n
  648. \\setlength{\\emergencystretch}{10pt}\n\n
  649. \\title{` + document.getElementById("name").value + "}" +
  650. `\\hypersetup{pageanchor=false}
  651. \\setlength\\parskip{1em}\n
  652. \\begin{document}\n
  653. \\maketitle\n
  654. \\newpage\n
  655. \\thispagestyle{empty}\n
  656. \n
  657. \\newpage\n
  658. \\setcounter{page}{1}\n`;
  659. footer = '\\end{document}';
  660. }else if(template_id == 4){
  661. header = document.querySelector('.start').value;
  662. footer = document.querySelector('.end').value;
  663. }
  664. }
  665. function download_file(){
  666. let editor_content;
  667. if(is_visual_editor){
  668. remove_mathjax();
  669. editor_content = visual_editor.get_text();
  670. editor_content = (new html2tedi()).convert(editor_content);
  671. array_b64_images = visual_editor.get_images_b64();
  672. reload_mathjax();
  673. }else
  674. editor_content = code_editor.get_text_code();
  675. if(array_b64_images.length == 0)
  676. array_b64_images = visual_editor.get_images_b64();
  677. editor_content = editor_content.replace(/&lt;/g, "<");
  678. editor_content = editor_content.replace(/&gt;/g, ">");
  679. editor_content = editor_content.replace(/&nbsp;/g, " ");
  680. generate(editor_content, array_b64_images);
  681. }
  682. function drop(e){
  683. let files = e.dataTransfer.files;
  684. if(files[0].type === "application/zip"){
  685. load_file(files[0]);
  686. }
  687. }
  688. function generate(text, b64_images, index_filename = "index.te") {
  689. var zip = new JSZip();
  690. zip.file(index_filename, text);
  691. var array_length = b64_images.length;
  692. for(var i = 0; i < array_length; ++i){
  693. var b64 = b64_images[i].search("base64");
  694. var buf = atob(b64_images[i].substring(b64 + 7, b64_images[i].length));
  695. zip.file("image" + i, b64_images[i].substring(b64 + 7, b64_images[i].length), {base64: true});
  696. }
  697. zip.generateAsync({type:"blob"})
  698. .then(function(content) {
  699. const title = document.getElementById('title');
  700. if(url_canonical != "" && document.getElementById('save-api').checked){
  701. let formData = new FormData();
  702. formData.append("fileToUpload", new File([content], title.innerText + ".zip"));
  703. formData.append("token", document.getElementById('api-token').value);
  704. let xhr = new XMLHttpRequest();
  705. xhr.open('POST', url_canonical, true);
  706. xhr.send(formData);
  707. }else{
  708. saveAs(content, title.innerText + ".zip");
  709. }
  710. });
  711. }
  712. function load_file(file){
  713. let zip = new JSZip();
  714. set_loading_file_popup_visibility(true);
  715. zip.loadAsync(file).then(function(contents) {
  716. var zip_files_count = Object.keys(contents.files).length;
  717. var e = 0;
  718. var index_file = false;
  719. Object.keys(contents.files).forEach(function(filename) {
  720. if(filename == "index.te"){
  721. zip.file(filename).async('string').then(function(file_content) {
  722. let s = file_content;
  723. s = s.replace(/&nbsp;/g, " ");
  724. s = s.replace(/</g, "&lt;");
  725. s = s.replace(/>/g, "&gt;");
  726. code_editor.set_text_code(s);
  727. index_file = true;
  728. e += 1;
  729. if(e == zip_files_count){
  730. if(!index_file)
  731. fail_found("<br>Couldn't load uploaded file correctly");
  732. let text = code_editor.get_text_code();
  733. text = (new tedi2html()).convert(text);
  734. visual_editor.set_images_b64(array_b64_images);
  735. visual_editor.set_text(text);
  736. if(is_visual_editor)
  737. reload_mathjax();
  738. change_input();
  739. set_loading_file_popup_visibility(false);
  740. }
  741. });
  742. }else{
  743. zip.file(filename).async('base64').then(function(file_content) {
  744. var file_content_text = atob(file_content);
  745. let position = 5;
  746. if(isNaN(parseInt(filename.substring(position, filename.length))))
  747. position = 6;
  748. let image_num = parseInt(filename.substring(position, filename.length));
  749. if(/%!PS-Adobe-3.0/.test(file_content_text)){
  750. array_b64_images[image_num] = "data:image/x-eps;base64," + file_content;
  751. }else if(/<dc:format>image\/svg\+xml<\/dc:format>/.test(file_content_text) ||
  752. /<svg/.test(file_content_text)){
  753. array_b64_images[image_num] = "data:image/svg+xml;base64," + file_content;
  754. }else{
  755. array_b64_images[image_num] = "data:image/jpeg;base64," + file_content;
  756. }
  757. e += 1;
  758. if(e == zip_files_count){
  759. if(!index_file)
  760. fail_found("<br>Couldn't load uploaded file correctly");
  761. let text = code_editor.get_text_code();
  762. text = (new tedi2html()).convert(text);
  763. visual_editor.set_images_b64(array_b64_images);
  764. visual_editor.set_text(text);
  765. if(is_visual_editor)
  766. reload_mathjax();
  767. change_input();
  768. set_loading_file_popup_visibility(false);
  769. }
  770. });
  771. }
  772. });
  773. }, function(error) {
  774. fail_found("<br>Couldn't load uploaded file" . error);
  775. set_loading_file_popup_visibility(false);
  776. });
  777. }
  778. function set_collab(){
  779. if(!is_collab){
  780. var script = document.createElement("script");
  781. script.src = "js/togetherjs.js";
  782. script.id = "tjs-js";
  783. document.head.appendChild(script);
  784. setTimeout(set_togetherjs, 1000);
  785. is_collab = true;
  786. let tjs = document.getElementsByClassName('tjs');
  787. for(let i = 0; i < tjs.length; ++i)
  788. tjs[i].style.display = 'flex';
  789. }
  790. }
  791. function set_mathjax(){
  792. if(is_mathjax){
  793. try{
  794. remove_mathjax();
  795. }catch(e){}
  796. is_mathjax = false;
  797. }else{
  798. is_mathjax = true;
  799. reload_mathjax();
  800. }
  801. }
  802. function set_togetherjs(){
  803. TogetherJSConfig_hubBase = "https://togetherjs-hub.glitch.me/";
  804. TogetherJs_enableAnalytics = false;
  805. TogetherJSConfig_disableWebRTC = true;
  806. TogetherJSConfig_youtube = false;
  807. TogetherJSConfig_ignoreForms = true;
  808. TogetherJSConfig_dontShowClicks = true;
  809. TogetherJS.hub.on("text-send", function (msg) {
  810. if(!msg.sameUrl) {
  811. return;
  812. }
  813. document.getElementById('visual-editor').innerHTML = msg.output;
  814. log_text(msg.output);
  815. });
  816. let element = document.getElementById('visual-editor');
  817. element.addEventListener('keyup', function (event) {
  818. // grab text for sending as a message to collaborate
  819. var sharedtext = element.innerHTML;
  820. if(TogetherJS.running) {
  821. TogetherJS.send({
  822. type: "text-send",
  823. output: sharedtext
  824. });
  825. log_text(sharedtext);
  826. }
  827. });
  828. }
  829. function editor2pdf(){
  830. let s = "";
  831. if(is_visual_editor){
  832. let pdf_icon = visual_editor.element.querySelector('.pdf');
  833. pdf_icon.style.display = "none";
  834. let pdf_disabled_icon = visual_editor.element.querySelector('.pdf-disabled');
  835. pdf_disabled_icon.style.display = "flex";
  836. s = visual_editor.get_text();
  837. array_b64_images = visual_editor.get_images_b64();
  838. s = (new html2tedi()).convert(s);
  839. } else {
  840. s = code_editor.get_text();
  841. }
  842. s = s.replace(/&lt;/g, "<");
  843. s = s.replace(/&gt;/g, ">");
  844. s = (new tedi2tex()).convert(s, header, footer);
  845. s = s.replace(/&amp;/g, "&");
  846. var httpRequest = new XMLHttpRequest();
  847. httpRequest.onreadystatechange = function (data) {
  848. if(httpRequest.readyState == 4) {
  849. if(httpRequest.status == 200){
  850. var pdf_icon = document.querySelector('.pdf');
  851. pdf_icon.style.display = "flex";
  852. var pdf_disabled_icon = document.querySelector('.pdf-disabled');
  853. pdf_disabled_icon.style.display = "none";
  854. var options = {disablePageMode: true};
  855. if(!PDFObject.supportsPDFs){
  856. let downloadLink = document.createElement("a");
  857. downloadLink.href = "data:application/pdf;base64," + JSON.parse(httpRequest.response).content;
  858. downloadLink.download = Math.floor(Date.now() / 1000) + ".pdf";
  859. downloadLink.click();
  860. }else{
  861. PDFObject.embed("data:application/pdf;base64," + JSON.parse(httpRequest.response).content, "#pdf", options);
  862. document.querySelector("#pdf").style.display = "flex";
  863. document.querySelector(".close_pdf").style.display = "flex";
  864. }
  865. }else if(httpRequest.status == 0){
  866. let pdf_icon = visual_editor.element.querySelector('.pdf');
  867. window.print();
  868. }else{
  869. fail_found(JSON.parse(httpRequest.response).er);
  870. let pdf_icon = visual_editor.element.querySelector('.pdf');
  871. pdf_icon.style.display = "flex";
  872. let pdf_disabled_icon = visual_editor.element.querySelector('.pdf-disabled');
  873. pdf_disabled_icon.style.display = "none";
  874. }
  875. }
  876. };
  877. httpRequest.open('POST', api_address);
  878. httpRequest.setRequestHeader('Content-Type', 'application/json');
  879. let data = {'content': s , 'images_array': array_b64_images };
  880. httpRequest.send(JSON.stringify(data));
  881. }
  882. function close_pdf_viewer(){
  883. document.querySelector("#pdf").style.display = "none";
  884. document.querySelector(".close_pdf").style.display = "none";
  885. }
  886. function select_bookmark(element_text, header_number, header_position){
  887. if(is_visual_editor){
  888. let a = document.getElementById("visual-editor").querySelector(".visual-editor").querySelectorAll("div > h" + header_number);
  889. let selection = window.getSelection();
  890. let range = document.createRange();
  891. if(element_text.includes(a[header_position].innerText)){
  892. if(!visual_editor.is_scrolled_into_view(a[header_position]))
  893. a[header_position].scrollIntoView();
  894. range.selectNode(a[header_position]);
  895. selection.removeAllRanges();
  896. selection.addRange(range);
  897. }
  898. }else{
  899. let a = document.getElementById("code-editor").querySelector(".visual-editor").querySelectorAll("div");
  900. let selection = window.getSelection();
  901. let range = document.createRange();
  902. for(let i = 0; i < a.length; ++i){
  903. if(a[i].innerText.length > 0 && element_text.length > 0){
  904. if(a[i].innerText.includes(element_text)){
  905. if(!code_editor.is_scrolled_into_view(a[i]))
  906. a[i].scrollIntoView();
  907. range.selectNode(a[i]);
  908. selection.removeAllRanges();
  909. selection.addRange(range);
  910. }
  911. }
  912. }
  913. }
  914. }
  915. function insert_bookmark(text, element_name, number){
  916. var p = document.querySelector(".bookmark-links");
  917. var link = document.createElement("a");
  918. link.appendChild(document.createTextNode(text));
  919. link.setAttribute("onclick", "select_bookmark('" + text + "'," + element_name + ", " + number + ")");
  920. link.setAttribute("class", "header" + element_name);
  921. p.appendChild(link);
  922. p.appendChild(document.createElement("br"));
  923. }
  924. function export_markdown(){
  925. let editor_content;
  926. if(is_visual_editor){
  927. editor_content = visual_editor.get_text();
  928. editor_content = (new html2tedi()).convert(editor_content);
  929. array_b64_images = visual_editor.get_images_b64();
  930. }else
  931. editor_content = code_editor.get_text_code();
  932. editor_content = editor_content.replace(/&lt;/g, "<");
  933. editor_content = editor_content.replace(/&gt;/g, ">");
  934. editor_content = editor_content.replace(/&nbsp;/g, " ");
  935. editor_content = (new tedi2md()).convert(editor_content);
  936. if(array_b64_images.length == 0)
  937. array_b64_images = visual_editor.get_images_b64();
  938. editor_content = editor_content.replace(/&lt;/g, "<");
  939. editor_content = editor_content.replace(/&gt;/g, ">");
  940. editor_content = editor_content.replace(/&nbsp;/g, " ");
  941. generate(editor_content, array_b64_images, "index.md");
  942. }
  943. function set_bookmarks(text){
  944. let p = document.querySelector('.bookmark-links');
  945. p.innerHTML = "";
  946. if(is_visual_editor){
  947. let position = text.regexIndexOf("<h");
  948. let position_end = text.regexIndexOf("</h");
  949. let titles_number = [0,0,0];
  950. while(position != -1 && position_end != -1){
  951. let level = text[position + 2];
  952. text = text.erase(position, 4);
  953. position_end = text.regexIndexOf("</h");
  954. text = text.erase(position_end, 5);
  955. insert_bookmark(text.substring(position, position_end), parseInt(level), titles_number[parseInt(level) - 1]);
  956. titles_number[parseInt(level) - 1] += 1;
  957. position = text.regexIndexOf("<h");
  958. position_end = text.regexIndexOf("</h");
  959. }
  960. }else{
  961. let position = text.regexIndexOf("#");
  962. let position_end = text.regexIndexOf("</div>", position);
  963. while(position != -1){
  964. insert_bookmark(text.substring(position, position_end));
  965. position = text.regexIndexOf("#", position_end);
  966. position_end = text.regexIndexOf("</div>", position);
  967. }
  968. }
  969. }