jslogo.js 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. var pe={},LANG={};
  2. if(location.href.substr(-2)=="hu") LANG={"Happy birthday":"Boldog szülinapot","Name?":"Neve?","Bad name!":"Hibás név!","Already exists!":"Már van ilyen!","Setup":"Beállítások","Start!":"Start!","Load":"Betölt","Save":"Lement","Reset":"Újrakezd","Tutorials":"Példák",'forward':"Előre",'backward':"Hátra",'left':"Balra fordul",'right':"Jobbra fordul",'pendown':"Farkinca le",'penup':"Farkinca fel",'color':"Szín",'text':"Szöveg",'let':"Értékadás",'call':"Eljárás hívás",'if':"Elágazás",'repeat':"Ismétlés",'question':"Kérdés",'rand':"Véletlen",'alert':"Figyelmeztetés",'debug':"Hibakeresés","Add function":"Új eljárás","Delete function":"Eljárás törlése","Are you sure?":"Biztos vagy benne?","Variable":"Doboz","Prompt":"Kérdés","Expression":"Érték","pixels":"képpont","Default":"Alapért","Draw turtle":"Mutasd a teknőst","Debug execution":"Mutasd az utasításokat","Depth?":"Szintek száma?","How old are you?":"Hány éves vagy?","snowflake":"hópehely","wandering":"bóklászó","plant":"virág","curly":"íves","triangle":"háromszög","bdaycake":"torta","Empty expression":"Üres kifejezés","No such variable":"Nincs ilyen változó","Missing expression":"Hiányzó kifejezés","Unknown keyword":"Ismeretlen kulcsszó","Missing argument":"Hiányzó paraméter","Bad variable":"Hibás változónév","Unknown function":"Ismeretlen eljárás","Arguments mismatch":"Eltérő paraméterszám","Unknown command":"Ismeretlen parancs"};
  3. if(location.href.substr(-2)=="de") LANG={"Happy birthday":"Alles Gute zum Geburtstag","Name?":"Name?","Bad name!":"Schlechter Name!","Already exists!":"Ist bereits vorhanden!","Setup":"Konfiguration","Start!":"Anfang!","Load":"Einladen","Save":"Ersparen","Reset":"Neu setzen","Tutorials":"Lernprogrammen","forward":"vorantreiben","backward":"zurück","left":"links","right":"rechts","pendown":"hinlegen","penup":"hochheben","color":"kolorieren","text":"schreiben","let":"angeben","call":"erfolgen","if":"ob","repeat":"repetieren","question":"fragen","rand":"würfeln","alert":"warnen","debug":"debuggen","Add function":"Neue Funktion","Delete function":"Lösche Funktion","Are you sure?":"Bist du sicher?","Variable":"Variable","Prompt":"Prompt","Expression":"Ausdruck","pixels":"Pixel","Default":"Default","Draw turtle":"Schildkröte anzeigen","Debug execution":"Ablaufverfolgung ausführen","Depth?":"Tiefe?","How old are you?":"Wie alt bist du?","snowflake":"Schneeflocke","wandering":"wandern","plant":"Pflanze","curly":"lockig","triangle":"Dreieck","bdaycake":"Gtagskuchen","Empty expression":"Leerer Ausdruck","No such variable":"Keine solche Variable","Missing expression":"Fehlender Ausdruck","Unknown keyword":"Unbekanntes Schlüsselwort","Missing argument":"Fehlendes Argument","Bad variable":"Schlechte Variable","Unknown function":"Unbekannte Funktion","Arguments mismatch":"Argumente stimmel nicht","Unknown command":"Unbekannter Befehl"};
  4. if(location.href.substr(-2)=="fr") LANG={"Happy birthday":"Bon anniversaire","Name?":"Prénom?","Bad name!":"Mauvais nom!","Already exists!":"Existe déjá!","Setup":"Configuration","Start!":"Début!","Load":"Charge","Save":"Enregistrer","Reset":"Réinitialiser","Tutorials":"Tutoriels","forward":"envoyer","backward":"arriéré","left":"gauche","right":"droite","pendown":"soulever","penup":"relever","color":"colorizer","text":"écrire","let":"attributer","call":"invoquer","if":"si","repeat":"répéter","question":"question","rand":"randomiser","alert":"alerte","debug":"déboguer","Add function":"Ajouter une fonction","Delete function":"Supprimer la fonction","Are you sure?":"Étes-vous sűr?","Variable":"Variable","Prompt":"Sujet","Expression":"Expression","pixels":"pixels","Default":"Défaut","Draw turtle":"Montrer la tortue","Debug execution":"Suivre l'exécution","Depth?":"Profondeur?","How old are you?":"Quel áge avez-vous?","snowflake":"neige","wandering":"errant","plant":"plante","curly":"bouclé","triangle":"triangle","bdaycake":"gáteau","Empty expression":"Expression vide","No such variable":"Pas une telle variable","Missing expression":"Expression manquante","Unknown keyword":"Mot-clé inconnu","Missing argument":"Argument manquant","Bad variable":"Mauvaise variable","Unknown function":"Fonction inconnue","Arguments mismatch":"Incompatibilité des arguments","Unknown command":"Commande inconnnue"};
  5. function L(t){return LANG[t]!=null&&LANG[t]!=undefined?LANG[t]:(t!=null?t.replace(/_/g,' '):'');}
  6. pe.jslogo = {
  7. content:null,
  8. canvas:null,
  9. menu:null,
  10. working:null,
  11. turtle:null,
  12. drawturtle:true,
  13. debuglog:false,
  14. dragging:null,
  15. dragobj:null,
  16. pen:true,
  17. color:'#000000',
  18. filename:'noname.txt',
  19. args:null,
  20. tutorials:[
  21. {"name":"snowflake","preview":"iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX///8AAABVwtN+AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+EMBBEqLWwOQcsAAADRSURBVCjPY2AgGzRAaUYFKIMpAcoQUoEy6qyhDAdGdEYCM5RhwAYVMGBhBhnJuCGBme0AiCHgwMjiAGTISzswfokAMsx4GxhumAEZYBuZkBkGIAYfEEuAGBxALABjgKXYkBWDjAAT5iBGBRBzghgeIEvBjgQRQCcwNkB5YFEw7wCyGlkQIwJmYBluh7EhO0wCt8MUWBoYONRABko6MNypAjlMyIFRBeQwBgloaDB+SGBmPwB2ggALI1pgYoZzjjSUYaUHiyZYfDHD4ouxgexEAAAvFRuJBA7SdwAAAABJRU5ErkJggg==","code":"to koch(h,l)\nh=h/3\nif l [\nkoch(h,l-1)\nleft 60\nkoch(h,l-1)\nright 120\nkoch(h,l-1)\nleft 60\nkoch(h,l-1)\n] else [\nforward h\n]\nend\n\nquestion l,4,"+L('Depth?')+"\npenup\nforward h/6\nright 90\nbackward w/6\npendown\nrepeat 3 [\nkoch(w,l)\nright 120\n]\n"},
  22. {"name":"wandering","preview":"iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX///8AAABVwtN+AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+EMBBErEC19PJsAAAEuSURBVCjPY2CgHeCBMdigtEIdlFHZ2gAkmRkY/NgOABnsBxja+UAiPAcYDoIZHA0MCTIghn0Dg4EuSIsNA4PEX6hh/P8YIFIMAQw1DAyKQDMaGBzrGBQdGPgZGBzEGBQZGOQYGBKEGFQZGIw/MDhIgxjFHAwfuBtsgSIC/C/4GoAi1gbye3gO8DIw1C6wZzB5wMHAcO/B/+ZvD7IZGOY4PH4svSGvguFROuME1k6bZgbGPQwVzMft+xgYHjDwH/yt/4GBcQEDh73mdaBTEhg4Ev+9BXtNoP/7LYhnN36JAdH8Z5U1fEAMjl/VC8Ehwfv/zP9mEINPvSHJAcTgvM34BxIy7I1nIAzmAhMIg4n/CTTUGI/BGN1QBjMnlMFXCWXYH4AyWBqgDP4DNIxiBgD6AEnxd0Ab/QAAAABJRU5ErkJggg==","code":"repeat 200 [\nrand d,0,180\nright d\nrand l,10,50\nforward l\n]\n"},
  23. {"name":"plant","preview":"iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX///8AAABVwtN+AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+EMBBEpLDAkIp4AAAD9SURBVCjP5ZCxSgNBEIa/3ZzJRQ88ECRN5Ixa2KlYRLjitNcnsMgbaC/IxMpCMKWFyBUWPoKFaKwEHyIc1hZRQSyd3T2fwoWFj2H++YYBiKjfWlXDfSUBHr7HAT5u6srXJFTM0yR0x6v7Uw/zt92pa2pCW+4UTiSN5FDhExvJsUKP2fTM5a+we/Lj3XYobz7fMMMXCctcHJXEVqE8LYP28r3AeloXcqN+NmFnF622zrGJN+dsWzfieomOcZ7RHHGUESN96MSaeyxgYE1qBz0WxsaQpE1WhOcsszndgmWd+eqgncABiwUzI7d5q8CoZItGpXLo+yvo3/gD/iH8AgNrM399JvyrAAAAAElFTkSuQmCC","code":"to plant(s,a)\nif s>5 [\nright a\nforward s\nrepeat 4 [\nrand d,20,160\nleft 90\nplant(s/2,d)\nright 90\n]\nbackward s\nleft a\n] else [\n]\nend\n\nplant(100,0)\n"},
  24. {"name":"curly","preview":"iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX///8AAABVwtN+AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+EMBBEeDnVDw04AAADFSURBVCjPY2DABuwgFDvDwQYwg/sggwOE0SgAZRyyXwBmcLbYK4AZHixQhiuLPkTKjUUdotjziADEHAMbfojJB1hgVsEZTBgMRgaGH1AGMzvEgAYZqEMaEhggtjk2MAiAGUoMDBxghgjMUA4GPohZAgyGjVDG4UQwQ4FRGeIkB0b/CRAGk/4JMKOB6X8HlBEPZjAyQEWAjPiPEPcwmQZCnMootgjKEHCCOv58C5RhwAFl8BhAGcwHsPsUk8FCGYMHg0EjAAD9IyJDS3urWAAAAABJRU5ErkJggg==","code":"to curly(s)\nif s>1 [\nrepeat 360 [\nif repcount=10 [\nleft 90\ncurly(s/2)\nright 90\n] else [\n]\nforward s\nright repcount\n]\nright 180\n] else [\n]\nend\n\ncurly(20)\n"},
  25. {"name":"triangle","preview":"iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX///8AAABVwtN+AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+EMBBEZKOgP0HQAAAEqSURBVCjPnc+xSsNQFMbx7/bGJGgwHURrjYk4FRQJFrRgqH2J7hkko3TSDkXzCK5uzgoidCm6ZBX6EJmdsogdSuPJvScPoHe5v+n8+YC/vrRGxr8YMGReI2RYoxoLhtNieB7Djxinh4zzW8Z9jfknVzOhIXKuilxm3DRjjbe1ETfdQjcdW1c3HU/D9yNd3emfHCtcdG8ShaOfYanjZalBIV19ouMVBJ1VVdEEVFXO6Hi1XtJOVbWWQFDBdIBWj7DRBqIOIQgIE8LeFEiuq/hHitUX4bJMoapxtVSqJi1tULWollopxIMMGwfGAGImQyumqlxaC6twc5iGYdvNZgjTdGhpL4S73t7eijpjuIHv96PJGLuP0+5ZcjXH/vvL9/Du+VXtpLdCjH+8X8C6UIoQeMzdAAAAAElFTkSuQmCC","code":"to sierpinski(n,l)\nif n>0 and l>1 [\nrepeat 3 [\nsierpinski(n-1,l/2)\nforward l\nright 120\n]\n] else [\n]\nend\n\nquestion n,5,"+L('Depth?')+"\npenup\nright 30\nbackward h/4\npendown\nsierpinski(n,h/2)\n"},
  26. {"name":"bdaycake","preview":"iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAAAFVBMVEV6KxiIQC5CaFDDwr7e3Nb99NH9//zV4jmHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+EMBBEWG9BHra0AAACTSURBVEjH7ZRNCoAgEEanTetm0wG6gtIFHLxBXkCd+x8hUbEfSFtbg+Lj8wmiInCj4Bc6E3zoJrZMW6Ei+BybGx2Cj7EpgrkJLq/ThVKWhDXEjp1KZNkmsu5RsB0KREKSUqTEmWQgsUjSwIiAOA1xgOFCC+IMDNUaexGwWuEcdOvZN4W1Oq9f7OEjd9EU/p/2Q8IOHD5HGuMevwoAAAAASUVORK5CYII=","code":"to doboz(sz,m)\nforward sz\nleft 90\nforward m\nleft 90\nforward sz\nleft 90\nforward m\nleft 90\nend\n\nto gyertya()\npendown\ncolor #000000\ndoboz(10,50)\nleft 90\nforward 50\nright 90\nforward 5\ncolor #e9cb24\nleft 60\nforward 10\nleft 45\nforward 15\nleft 150\nforward 15\nleft 45\nforward 10\nright 30\npenup\nforward 50\nleft 90\nend\n\nquestion n,8,"+L('How old are you?')+"\npenup\nbackward 100\nright 90\nbackward 20*n+10\npendown\ncolor #742919\nrepeat 50 [\nforward 40*n+20\nbackward 40*n+20\nleft 90\nforward 1\nright 90\n]\ndoboz(40*n+20,20)\nleft 90\nforward 20\nright 90\nrepeat 50 [\nforward 40*n+20\nbackward 40*n+20\nleft 90\nforward 1\nright 90\n]\npenup\nforward 10\nrepeat n [\nforward 15\ngyertya()\nforward 15\n]\n"}
  27. ],
  28. init:function(cfg) {
  29. pe.jslogo.turtle=new Image();
  30. pe.jslogo.turtle.src='images/jslogo/turtle.png';
  31. pe.jslogo.turtle.width=16;
  32. pe.jslogo.turtle.height=16;
  33. pe.jslogo.content=document.getElementById('content');
  34. if(pe.jslogo.content==null) {
  35. pe.jslogo.content=document.createElement('div');
  36. pe.jslogo.content.id='content';
  37. document.body.appendChild(pe.jslogo.content);
  38. }
  39. var logo=document.createElement('div'),bg=document.createElement('div'),inp=document.createElement('div'),w=document.createElement('div');
  40. bg.setAttribute('id','bgdiv');
  41. bg.style='position:fixed;top:0px;left:0px;width:100%;height:100%;background:rgba(0,0,0,0.2);z-index:9;';
  42. bg.onclick=pe.jslogo.main;
  43. logo.innerHTML='<img src="images/jslogo/logo.gif" style="float:left;"><h1>JSLogo</h1><b>Logo Interpreter<br>by bzt<br><br><br>'+L('Happy birthday')+' Bende!</b>';
  44. logo.style='position:fixed;top:50%;left:50%;margin-top:-210px;margin-left:-310px;width:600px;border:outset 1px;padding:10px;z-index:10;background:#ffffff;';
  45. logo.onclick=pe.jslogo.main;
  46. document.body.appendChild(bg);
  47. pe.jslogo.content.appendChild(logo);
  48. inp.setAttribute('id','inp');
  49. inp.setAttribute('style','display:none;');
  50. document.body.appendChild(inp);
  51. w.style='position:fixed;top:0px;left:0px;width:100%;height:100%;z-index:99;opacity:0.3;visibility:hidden;';
  52. w.innerHTML='<img style="position:fixed;bottom:0px;right:0px;" src="images/jslogo/working.png">';
  53. document.body.appendChild(w);
  54. pe.jslogo.working=w;
  55. window.addEventListener( "mousemove", pe.jslogo.display, false );
  56. window.addEventListener( "mouseup", pe.jslogo.drop, false );
  57. },
  58. display:function(e) {
  59. if(pe.jslogo.dragobj!=null) {
  60. pe.jslogo.dragging=pe.jslogo.dragobj.cloneNode(true);
  61. if(pe.jslogo.dragobj.tagName!='IMG' && e.ctrlKey==false && e.shiftKey==false) {
  62. try{pe.jslogo.dragobj.parentNode.removeChild(pe.jslogo.dragobj);}catch(e){};
  63. }
  64. pe.jslogo.dragobj=null;
  65. pe.jslogo.dragging.setAttribute('style','position:absolute;z-index:999;left:0px;top:0px;margin:0px;opacity:0.8;');
  66. document.body.appendChild(pe.jslogo.dragging);
  67. }
  68. if(pe.jslogo.dragging!=null){
  69. if(e!=null){
  70. if(e.pageX) {
  71. ml=e.pageX;mt=e.pageY;
  72. } else {
  73. ml=(event.clientX + document.body.scrollLeft);mt=(event.clientY+document.body.scrollTop);
  74. }
  75. }
  76. pe.jslogo.dragging.style.left=Math.floor(ml+10)+'px';
  77. pe.jslogo.dragging.style.top=Math.floor(mt+10)+'px';
  78. }
  79. },
  80. drag:function(event,obj) {
  81. if(obj==null) obj=event.target;
  82. pe.jslogo.dragobj=obj;
  83. return false;
  84. },
  85. drop:function(e,ctx) {
  86. pe.jslogo.dragobj=null;
  87. if(pe.jslogo.dragging!=null) {
  88. var cmd,args,obj;
  89. if(pe.jslogo.dragging.tagName=='IMG') {
  90. cmd=pe.jslogo.dragging.getAttribute('data-cmd'); args=null; obj=null;
  91. } else {
  92. var img=pe.jslogo.dragging.getElementsByTagName('IMG')[0];
  93. cmd=img.getAttribute('data-cmd'); args=img.nextSibling.innerHTML; obj=pe.jslogo.dragging.cloneNode(true);
  94. }
  95. if(ctx!=null) {
  96. var i, bef=null, divs=document.getElementById("editor").getElementsByTagName('*');
  97. for(i=0;i<divs.length;i++) {
  98. if(divs[i].className=='cmd' && Math.round(divs[i].style.paddingTop.replace('px',''))) {
  99. divs[i].style.paddingTop='0px'; bef=divs[i];
  100. }
  101. }
  102. }
  103. try{document.body.removeChild(pe.jslogo.dragging);}catch(e){} pe.jslogo.dragging=null;
  104. if(ctx!=null)
  105. pe.jslogo.addcmd(ctx, cmd, args, bef, obj);
  106. }
  107. pe.jslogo.dropbefore(e);
  108. return false;
  109. },
  110. dropbefore:function(e) {
  111. var i, divs;
  112. try{divs=document.getElementById("editor").getElementsByTagName('*');}catch(e){return true;};
  113. for(i=0;i<divs.length;i++) {
  114. if(divs[i].className=='cmd')
  115. divs[i].style.paddingTop='0px';
  116. }
  117. if(e.type=='mouseover' && pe.jslogo.dragging!=null) {
  118. if( e.target.className=='cmd') e.target.style.paddingTop='20px'; else
  119. if( e.target.parentNode.className=='cmd') e.target.parentNode.style.paddingTop='20px';
  120. }
  121. return true;
  122. },
  123. setargs:function(evt,cmd,val) {
  124. if(pe.jslogo.args==null) return;
  125. if(cmd=='color' && val=='') val='#000000';
  126. pe.jslogo.args.innerHTML=val;
  127. if(evt!=null&&evt.keyCode==13) pe.jslogo.main();
  128. },
  129. setdeg:function() {
  130. var cvs=document.getElementById('deg'),ctx;
  131. if(cvs==null) return;
  132. var obj=cvs.previousSibling.previousSibling.previousSibling;
  133. var r=Math.round(obj.value);
  134. cvs.width=180;cvs.height=180;ctx=cvs.getContext('2d');ctx.scale(1,1); ctx.clearRect(0,0,180,180);
  135. ctx.beginPath(); ctx.strokeStyle='#000000';ctx.lineWidth=1;ctx.arc(90,90,89,0,2*Math.PI,false); ctx.stroke();
  136. ctx.translate(90,90); ctx.beginPath(); ctx.moveTo(0,0); ctx.strokeStyle='#F0F0FF'; ctx.fillStyle='#F0F0FF'; ctx.lineTo(0,-89); ctx.stroke();
  137. ctx.beginPath(); ctx.moveTo(0,0);
  138. if(obj.getAttribute('data-dir')!='right') { r=Math.round(360-r); if(r!=360) ctx.arc(0,0,60,r*Math.PI/180.0-Math.PI/2,-Math.PI/2,false); }
  139. else { ctx.arc(0,0,60,-Math.PI/2,r*Math.PI/180.0-Math.PI/2,false); }
  140. ctx.fill(); ctx.beginPath(); ctx.moveTo(0,0);
  141. ctx.rotate(r*Math.PI/180.0); ctx.strokeStyle='#000000'; ctx.lineWidth=3; ctx.lineTo(0,-85);
  142. ctx.moveTo(0,-84); ctx.lineTo(5,-79); ctx.lineTo(-5,-79); ctx.lineTo(0,-84); ctx.stroke();
  143. },
  144. getdeg:function(event) {
  145. var cvs=document.getElementById('deg'),obj,pos,x,y,r;
  146. if(cvs==null||event.buttons==0) return;
  147. obj=cvs.previousSibling.previousSibling.previousSibling;
  148. pos=cvs.getBoundingClientRect();
  149. x=event.clientX-Math.round(pos.left)-90;
  150. y=event.clientY-Math.round(pos.top)-90;
  151. r=Math.round(Math.atan2(y,x)*180.0/Math.PI)+90; if(r<0) r+=360;
  152. if(obj.getAttribute('data-dir')=='right')
  153. obj.value=r;
  154. else
  155. obj.value=Math.round(360-r);
  156. pe.jslogo.setargs(event,obj.getAttribute('data-dir'),obj.value);
  157. pe.jslogo.setdeg();
  158. },
  159. getargs:function(obj) {
  160. var a,txt,cmd=obj.getAttribute('data-cmd'),val,pos=obj.getBoundingClientRect(),inp=document.getElementById('inp');
  161. if(obj.parentNode.className!=null && obj.parentNode.className.match(/error/)) {
  162. obj.parentNode.className=obj.parentNode.className.replace(' error','').trim();
  163. obj.parentNode.removeAttribute('title');
  164. }
  165. if(cmd=='pendown'||cmd=='penup') return;
  166. pe.jslogo.args=obj.nextSibling;
  167. val=pe.jslogo.args!=null&&pe.jslogo.args.innerHTML!=null?pe.jslogo.args.innerHTML.trim():''
  168. document.getElementById('bgdiv').style.display='block';
  169. inp.setAttribute('style','position:fixed;background:#ffffff;top:'+pos.top+';left:'+Math.round(pos.left+48)+'px;display:block;z-index:10;padding:5px;');
  170. txt='<b>'+L(cmd)+'</b><br>';
  171. if(cmd=='forward'||cmd=='backward') {
  172. if(val=='') val=0;
  173. txt+='<input type="text" style="width:60px;" value="'+val+'" onchange="if(this.value<0)this.value=0;pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\'));" onkeyup="if(this.value<0)this.value=0;pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\'));">'+L('pixels');
  174. } else
  175. if(cmd=='left'||cmd=='right') {
  176. if(val=='') val=0;
  177. txt+='<input type="text" data-dir="'+cmd+'" style="width:60px;" value="'+val+'" onchange="if(this.value>359)this.value-=360;if(this.value<0)this.value=Math.round(this.value)+360;pe.jslogo.setargs(event,\''+cmd+'\',this.value);pe.jslogo.setdeg();" onkeyup="if(this.value>359)this.value-=360;if(this.value<0)this.value=Math.round(this.value)+360;pe.jslogo.setargs(event,\''+cmd+'\',this.value);pe.jslogo.setdeg();">&deg;<br>';
  178. txt+='<canvas id="deg" style="cursor:crosshair;width:180px;height180px;" onmousedown="pe.jslogo.getdeg(event);" onmousemove="pe.jslogo.getdeg(event,this);">';
  179. } else
  180. if(cmd=='question') {
  181. var a=val.split(',');
  182. txt+=L('Variable')+':<input type="text" size="2" value="'+(a[0]?a[0]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\')+\',\'+this.nextSibling.nextSibling.value.replace(/,/gi,\'\')+\',\'+this.nextSibling.nextSibling.nextSibling.nextSibling.value.replace(/,/gi,\'\'));" onkeyup="pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\')+\',\'+this.nextSibling.nextSibling.value.replace(/,/gi,\'\')+\',\'+this.nextSibling.nextSibling.nextSibling.nextSibling.value.replace(/,/gi,\'\'));">,&nbsp;';
  183. txt+=L('Default')+':<input type="text" size="4" value="'+(a[1]?a[1]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\',\'+this.value.replace(/,/gi,\'\')+\',\'+this.nextSibling.nextSibling.value.replace(/,/gi,\'\'));" onkeyup="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\',\'+this.value.replace(/,/gi,\'\')+\',\'+this.nextSibling.nextSibling.value.replace(/,/gi,\'\'));">';
  184. txt+=L('Prompt')+':<input type="text" value="'+(a[2]?a[2]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\',\'+this.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\',\'+this.value.replace(/,/gi,\'\'));" onkeyup="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\',\'+this.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\',\'+this.value.replace(/,/gi,\'\'));">';
  185. } else
  186. if(cmd=='let') {
  187. var a=val.split('=');
  188. txt+=L('Variable')+':<input type="text" size="2" value="'+(a[0]?a[0]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\')+\'=\'+this.nextSibling.nextSibling.value.replace(/,/gi,\'\'));" onkeyup="pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\')+\'=\'+this.nextSibling.nextSibling.value.replace(/,/gi,\'\'));">,&nbsp;';
  189. txt+=L('Expression')+':<input type="text" value="'+(a[1]?a[1]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\'=\'+this.value.replace(/,/gi,\'\'));" onkeyup="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\'=\'+this.value.replace(/,/gi,\'\'));">';
  190. } else
  191. if(cmd=='call') {
  192. var a=[], i, tbl=document.getElementById("editor"), name, f,fp='',p='',c=0;
  193. f=val.substr(0,val.length-1); i=f.indexOf('('); if(i<0) i=f.length; a[0]=f.substr(0,i); a[1]=f.substring(i+1,f.length);
  194. name=(a[0]?a[0]:'');
  195. txt+='<select onchange="this.nextSibling.nextSibling.setAttribute(\'placeholder\',this.options[this.selectedIndex].getAttribute(\'data-pars\'));pe.jslogo.args.setAttribute(\'data-pars\',this.options[this.selectedIndex].getAttribute(\'data-pars\'));pe.jslogo.args.setAttribute(\'data-call\',this.selectedIndex+1);pe.jslogo.setargs(event,\''+cmd+'\',this.value+\'(\'+this.nextSibling.nextSibling.value+\')\');">';
  196. for(i=1;i<tbl.rows[1].cells.length;i++) {
  197. f=tbl.rows[1].cells[i].getAttribute('data-func');
  198. f=f.substr(0,f.length-1).split('(');
  199. if(i==1) {fp=f[0]; p=f[1];}
  200. txt+='<option value="'+f[0]+'" data-pars="'+f[1]+'" '+(f[0]==name?' selected':'')+'>'+f[0]+'</option>';
  201. }
  202. txt+='</select>(<input type="text" value="'+(a[1]?a[1]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.value+\'(\'+this.value+\')\');" onkeyup="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.value+\'(\'+this.value+\')\');" placeholder="'+p+'">)';
  203. pe.jslogo.args.setAttribute('data-pars',p);
  204. pe.jslogo.args.setAttribute('data-call',1);
  205. pe.jslogo.setargs(null,'call', (a[0]?a[0]:fp)+'('+(a[1]?a[1]:'')+')');
  206. } else
  207. if(cmd=='rand') {
  208. var a=val.split(',');
  209. txt+=L('Variable')+':<input type="text" size="2" value="'+(a[0]?a[0]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\')+\',\'+this.nextSibling.nextSibling.value+\',\'+this.nextSibling.nextSibling.nextSibling.nextSibling.value);" onkeyup="pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\')+\',\'+this.nextSibling.nextSibling.value+\',\'+this.nextSibling.nextSibling.nextSibling.nextSibling.value);">,&nbsp;';
  210. txt+='min:<input type="number" style="width:60px;" value="'+Math.round(a[1]?a[1]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\',\'+this.value+\',\'+this.nextSibling.nextSibling.value);">';
  211. txt+='max:<input type="number" style="width:60px;" value="'+Math.round(a[2]?a[2]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.previousSibling.previousSibling.value.replace(/,/gi,\'\')+\',\'+this.previousSibling.previousSibling.value+\',\'+this.value);">';
  212. } else
  213. if(cmd=='color') {
  214. if(val=='') { val='#000000'; pe.jslogo.setargs(null,cmd,val); }
  215. txt+='<input type="color" value="'+val+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.value);">';
  216. } else
  217. if(cmd=='text') {
  218. var a=val.split(','),s=[8,10,12,16,24,36,48];
  219. txt+='<select onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.value+\',\'+this.nextSibling.nextSibling.value.replace(/,/gi,\'\'));">';
  220. if(a[0]==null||a[0]<8) a[0]=16;
  221. for(i=0;i<s.length;i++) {
  222. txt+='<option value="'+s[i]+'"'+(s[i]==a[0]?' selected':'')+'>'+s[i]+'</option>';
  223. }
  224. txt+='</select>(<input type="text" value="'+(a[1]?a[1]:'')+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.value+\',\'+this.value.replace(/,/gi,\'\'));" onkeyup="pe.jslogo.setargs(event,\''+cmd+'\',this.previousSibling.previousSibling.value+\',\'+this.value.replace(/,/gi,\'\'));">';
  225. } else
  226. txt+='<input type="text" value="'+val+'" onchange="pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\'));" onkeyup="pe.jslogo.setargs(event,\''+cmd+'\',this.value.replace(/,/gi,\'\'));">';
  227. inp.innerHTML=txt;
  228. if(cmd=='left'||cmd=='right') pe.jslogo.setdeg();
  229. inp.getElementsByTagName('INPUT')[0].focus();
  230. inp.getElementsByTagName('INPUT')[0].select();
  231. return false;
  232. },
  233. addcmd:function(func,cmd,args,bef,obj) {
  234. if(bef!=null) func=bef.parentNode;
  235. if(func!=null) {
  236. if(obj==null){
  237. obj=document.createElement('div');
  238. if(cmd=='if') {
  239. obj.innerHTML='<table class="if"><tr><th class="if" colspan="2"><img draggable=false src="images/jslogo/'+cmd+'.png" data-cmd="'+cmd+'" onmousedown="return pe.jslogo.drag(event,this.parentNode.parentNode.parentNode.parentNode.parentNode);" onclick="pe.jslogo.getargs(this);"><span></span></th><tr><td class="if" onmouseup="return pe.jslogo.drop(event,this);"></td><td class="if" onmouseup="return pe.jslogo.drop(event,this);"></td></tr></table>';
  240. } else if(cmd=='repeat') {
  241. obj.innerHTML='<table class="repeat"><tr><th class="repeat"><img draggable=false src="images/jslogo/'+cmd+'.png" data-cmd="'+cmd+'" onmousedown="return pe.jslogo.drag(event,this.parentNode.parentNode.parentNode.parentNode.parentNode);" onclick="pe.jslogo.getargs(this);"><span></span></th><tr><td class="repeat" onmouseup="return pe.jslogo.drop(event,this);"></td></tr></table>';
  242. } else {
  243. obj.innerHTML='<img draggable=false src="images/jslogo/'+cmd+'.png" data-cmd="'+cmd+'" onmousedown="return pe.jslogo.drag(event,this.parentNode);" onclick="return pe.jslogo.getargs(this);"><span></span>';
  244. }
  245. }
  246. obj.setAttribute('onmouseover','pe.jslogo.dropbefore(event);');
  247. obj.setAttribute('onmouseout','pe.jslogo.dropbefore(event);');
  248. obj.setAttribute('style','margin-top:0px;');
  249. obj.setAttribute('class','cmd');
  250. obj.setAttribute('draggable','false');
  251. if(bef!=null)
  252. func.insertBefore(obj,bef);
  253. else
  254. func.appendChild(obj);
  255. if(args==null)
  256. pe.jslogo.getargs(obj.getElementsByTagName('IMG')[0]);
  257. }
  258. },
  259. addfunc:function(name) {
  260. var i,tbl=document.getElementById("editor"), th=document.createElement('th'), td=document.createElement('td');
  261. if(name==null||name=='') name=prompt(L('Name?'));
  262. if(name==null||name=='') return;
  263. if(name.match(/^[a-z]+$/)) name+='()';
  264. if(!name.match(/^([a-z]+)\(([a-z,]*)\)$/)) { alert(L('Bad name!')); return; }
  265. var func=name.substr(0,name.indexOf('('));
  266. for(i=0;i<tbl.rows[0].cells.length;i++) { var a=tbl.rows[1].cells[i].getAttribute('data-func');
  267. if(a.substr(0,a.indexOf('('))==func) {alert(L('Already exists!')); return; } }
  268. th.setAttribute('data-func', name);
  269. th.setAttribute('class', 'func');
  270. th.innerHTML=name+'<img src="images/jslogo/delfunc.png" style="float:right;vertical-align:middle;cursor:pointer;" onclick="pe.jslogo.delfunc(this.parentNode);" title="'+L('Delete function')+'">';
  271. td.setAttribute('data-func', name);
  272. td.setAttribute('class', 'func');
  273. td.setAttribute('onmouseup','return pe.jslogo.drop(event,this);');
  274. tbl.rows[0].appendChild(th);
  275. tbl.rows[1].appendChild(td);
  276. return td;
  277. },
  278. delfunc:function(th) {
  279. var i, j, tbl=document.getElementById("editor"), name=th.getAttribute('data-func');
  280. if(!confirm(L('Are you sure?'))) return;
  281. for(i=0;i<tbl.rows[0].cells.length;i++) { if(tbl.rows[1].cells[i].getAttribute('data-func')==name) break; }
  282. if(i>0) {
  283. tbl.rows[0].removeChild(tbl.rows[0].cells[i]);
  284. tbl.rows[1].removeChild(tbl.rows[1].cells[i]);
  285. }
  286. tbl=document.getElementById("editor").getElementsByTagName('*');
  287. for(j=0;j<tbl.length;j++) {
  288. if(tbl[j].getAttribute('data-call')!=null && tbl[j].getAttribute('data-call')==i) {
  289. tbl[j].parentNode.className+=' error';
  290. }
  291. }
  292. },
  293. clearerr:function() {
  294. var i, tbl=document.getElementById("editor").getElementsByTagName('*');
  295. for(i=0;i<tbl.length;i++) {
  296. if(tbl[i].className!=null && tbl[i].className.match(/error/)) {
  297. tbl[i].className=tbl[i].className.replace(' error','').trim();
  298. tbl[i].removeAttribute('title');
  299. }
  300. }
  301. },
  302. lgo2dom:function(name, txt) {
  303. pe.jslogo.filename=name;
  304. pe.jslogo.menu=null;
  305. pe.jslogo.main();
  306. var i,j,a=[],v=[],lines=txt.split('\n'),line,tbl=document.getElementById("editor"),obj=tbl.rows[1].cells[0],cmd,args,ext,html='';
  307. for(i=0;i<lines.length;i++) {
  308. line=lines[i].trim();
  309. if(line=='') continue;
  310. if(line.substr(0,3)=='to ') {
  311. obj=pe.jslogo.addfunc(line.substring(3,line.length));
  312. } else
  313. if(line=='end') {
  314. obj.innerHTML=html;
  315. obj=tbl.rows[1].cells[0];
  316. html='';
  317. } else {
  318. if(line.match(/^[a-z]+=/)) { cmd='let'; args=line; } else
  319. if(line.match(/^[a-z]+\(/)) { cmd='call'; args=line; } else
  320. {j=line.indexOf(' '); if(j<0) j=line.length; cmd=line.substring(0,j); args=line.substring(j+1,line.length); }
  321. html+='<div onmouseover="pe.jslogo.dropbefore(event);" onmouseout="pe.jslogo.dropbefore(event);" style="margin-top:0px;" class="cmd" draggable="false">';
  322. if(cmd=='if') {
  323. html+='<table class="if"><tr><th class="if" colspan="2"><img draggable=false src="images/jslogo/'+cmd+'.png" data-cmd="'+cmd+'" onmousedown="return pe.jslogo.drag(event,this.parentNode.parentNode.parentNode.parentNode.parentNode);" onclick="pe.jslogo.getargs(this);"><span>'+args.substring(0,args.length-2)+'</span></th><tr><td class="if" onmouseup="return pe.jslogo.drop(event,this);">';
  324. } else
  325. if(cmd==']') {
  326. html+=args=='else ['?'</td><td class="if" onmouseup="return pe.jslogo.drop(event,this);">':'</td></tr></table>';
  327. } else
  328. if(cmd=='repeat') {
  329. html+='<table class="repeat"><tr><th class="repeat"><img draggable=false src="images/jslogo/'+cmd+'.png" data-cmd="'+cmd+'" onmousedown="return pe.jslogo.drag(event,this.parentNode.parentNode.parentNode.parentNode.parentNode);" onclick="pe.jslogo.getargs(this);"><span>'+args.substring(0,args.length-2)+'</span></th><tr><td class="repeat" onmouseup="return pe.jslogo.drop(event,this);">';
  330. } else {
  331. if(cmd=='call') {
  332. j=args.indexOf('('); if(j<0) j=args.length; a[0]=args.substr(0,j); a[1]=args.substr(j+1,args.length-1);
  333. for(j=1;j<tbl.rows[1].cells.length;j++) {
  334. v=tbl.rows[1].cells[j].getAttribute('data-func').split('(');
  335. if(a[0]==v[0]) {
  336. ext=' data-call="'+j+'" data-pars="'+v[1].substr(0,v[1].length-1)+'"';
  337. break;
  338. }
  339. }
  340. } else ext='';
  341. html+='<img draggable=false src="images/jslogo/'+cmd+'.png" data-cmd="'+cmd+'" onmousedown="return pe.jslogo.drag(event,this.parentNode);" onclick="return pe.jslogo.getargs(this);"><span'+ext+'>'+args+'</span>';
  342. }
  343. html+='</div>';
  344. }
  345. }
  346. obj.innerHTML=html;
  347. },
  348. load:function(files) {
  349. if(files.length<1 || files[0].size<1) return;
  350. var reader = new FileReader();
  351. reader.onload = function(e) {
  352. pe.jslogo.lgo2dom(files[0].name,e.target.result);
  353. };
  354. reader.readAsText(files[0]);
  355. },
  356. dom2lgo:function(obj,level) {
  357. var i,txt='';
  358. if(obj==null||obj.childNodes==null||obj.childNodes.length==0) return '';
  359. for(i=0;i<obj.childNodes.length;i++) {
  360. if(obj.childNodes[i]==null||obj.childNodes[i].firstChild==null) continue;
  361. if(obj.childNodes[i].firstChild.tagName=='TABLE') {
  362. //control structures
  363. cmd=obj.childNodes[i].firstChild.rows[0].cells[0].firstChild.getAttribute('data-cmd');
  364. args=obj.childNodes[i].firstChild.rows[0].cells[0].firstChild.nextSibling.innerHTML;
  365. txt+=' '.repeat(level)+cmd+' '+args.replace(/&gt;/gi,'>').replace(/&lt;/gi,'<')+' [\n';
  366. if(cmd=='repeat') {
  367. txt+=pe.jslogo.dom2lgo(obj.childNodes[i].firstChild.rows[1].cells[0],level+1);
  368. } else
  369. if(cmd=='if') {
  370. txt+=pe.jslogo.dom2lgo(obj.childNodes[i].firstChild.rows[1].cells[0],level+1);
  371. txt+=' '.repeat(level)+'] else [\n';
  372. txt+=pe.jslogo.dom2lgo(obj.childNodes[i].firstChild.rows[1].cells[1],level+1);
  373. }
  374. txt+=' '.repeat(level)+']\n';
  375. } else if(obj.childNodes[i].firstChild.tagName=='IMG') {
  376. cmd=obj.childNodes[i].firstChild.getAttribute('data-cmd');
  377. txt+=' '.repeat(level)+(cmd!='let'&&cmd!='call'?cmd+' ':'')+obj.childNodes[i].firstChild.nextSibling.innerHTML+'\n';
  378. }
  379. }
  380. return txt;
  381. },
  382. save:function() {
  383. var a=document.getElementById('download'), i, tbl=document.getElementById("editor"), txt='';
  384. if(pe.jslogo.filename==null||pe.jslogo.filename=='') pe.jslogo.filename='noname.txt';
  385. pe.jslogo.clearerr();
  386. for(i=1;i<tbl.rows[0].cells.length;i++) txt+='to '+tbl.rows[0].cells[i].getAttribute('data-func')+'\n'+pe.jslogo.dom2lgo(tbl.rows[1].cells[i],1)+'end\n\n';
  387. txt+=pe.jslogo.dom2lgo(tbl.rows[1].cells[0],0);
  388. a.setAttribute('href','data:text/plain;charset=UTF-8,' + encodeURIComponent(txt));
  389. a.setAttribute('download',pe.jslogo.filename);
  390. a.click();
  391. },
  392. setup:function() {
  393. var txt,inp=document.getElementById('inp');
  394. document.getElementById('bgdiv').style.display='block';
  395. inp.setAttribute('style','position:fixed;background:#ffffff;top:40%;left:40%;width:20%;height:20%;display:block;z-index:10;padding:5px;');
  396. txt='<b>'+L('Setup')+'</b><br>';
  397. txt+='<input type="text" value="'+pe.jslogo.filename+'" onchange="pe.jslogo.filename=this.value;" style="width:100%;"><br>';
  398. txt+='<input type="checkbox" id="setup1" value="1" onchange="pe.jslogo.drawturtle=this.checked;"'+(pe.jslogo.drawturtle?' checked':'')+'><label for="setup1">'+L('Draw turtle')+'</label><br>';
  399. txt+='<input type="checkbox" id="setup2" value="1" onchange="pe.jslogo.debuglog=this.checked;"'+(pe.jslogo.debuglog?' checked':'')+'><label for="setup2">'+L('Debug execution')+'</label><br>';
  400. inp.innerHTML=txt;
  401. },
  402. reset:function() {
  403. if(!confirm(L('Are you sure?'))) return;
  404. pe.jslogo.filename='noname.txt';
  405. pe.jslogo.menu=null;
  406. pe.jslogo.main();
  407. },
  408. tutorialselect:function() {
  409. var i,txt,inp=document.getElementById('inp');
  410. document.getElementById('bgdiv').style.display='block';
  411. inp.setAttribute('style','position:fixed;background:#ffffff;top:35%;left:40%;width:20%;display:block;z-index:10;padding:5px;');
  412. txt='<b>'+L('Tutorials')+'</b><br><div style="text-align:center;">';
  413. for(i=0;i<pe.jslogo.tutorials.length;i++)
  414. txt+='<div onclick="pe.jslogo.main();pe.jslogo.lgo2dom(pe.jslogo.tutorials['+i+'].name+\'.txt\',pe.jslogo.tutorials['+i+'].code);" style="display:inline-block;margin:5px;padding:5px;border:outset 2px;text-align:center;width:80px;cursor:pointer;"><img src="data:image/png;base64,'+pe.jslogo.tutorials[i].preview+'"><br>'+L(pe.jslogo.tutorials[i].name)+'</div>';
  415. txt+="</div>";
  416. inp.innerHTML=txt;
  417. },
  418. main:function() {
  419. document.getElementById('bgdiv').style.display='none';
  420. document.getElementById('inp').style.display='none';
  421. if(pe.jslogo.menu==null) {
  422. var cmd=['forward','backward','left','right','pendown','penup','color','text','let','call','if','repeat','question','rand','alert','debug'];
  423. pe.jslogo.content.innerHTML='';
  424. pe.jslogo.menu=document.createElement('div');
  425. pe.jslogo.menu.style='position:absolute;visibility:visible;height:95%;';
  426. var txt='<input id="upload" type="file" accept="text/*" style="display:none;" onchange="pe.jslogo.load(this.files);">';
  427. txt+='<a id="download" href="" style="display:none;" download></a>';
  428. txt+='<div id="menu"><b style="font-size:24px;">JSLogo</b><br><small>v1.0.0</small><hr>';
  429. txt+='<img src="images/jslogo/setup.png" style="cursor:pointer;" onclick="pe.jslogo.setup();" title="'+L('Setup')+'">';
  430. txt+='<img src="images/jslogo/play.png" style="cursor:pointer;" onclick="pe.jslogo.menu.style.visibility=\'hidden\';pe.jslogo.working.style.visibility=\'visible\';setTimeout(pe.jslogo.draw,10);" title="'+L('Start!')+'"><hr>';
  431. txt+='<img src="images/jslogo/load.png" style="cursor:pointer;" onclick="document.getElementById(\'upload\').click();" title="'+L('Load')+'">';
  432. txt+='<img src="images/jslogo/save.png" style="cursor:pointer;" onclick="pe.jslogo.save();" title="'+L('Save')+'">';
  433. txt+='<img src="images/jslogo/trash.png" style="cursor:pointer;" onclick="pe.jslogo.reset();" title="'+L('Reset')+'">';
  434. txt+='<img src="images/jslogo/tutorials.png" style="cursor:pointer;" onclick="pe.jslogo.tutorialselect();" title="'+L('Tutorials')+'">';
  435. txt+='<hr>';
  436. for(i=0;i<cmd.length;i++)
  437. txt+='<img src="images/jslogo/'+cmd[i]+'.png" data-cmd="'+cmd[i]+'" draggable=false onmousedown="return pe.jslogo.drag(event);" title="'+L(cmd[i])+'">';
  438. txt+='</div>';
  439. txt+='<img src="images/jslogo/addfunc.png" style="position:absolute;top:17px;right:-30px;cursor:pointer;" onclick="pe.jslogo.addfunc();" title="'+L('Add function')+'">';
  440. txt+='<table id="editor" border=1 cellspacing=0 cellpadding=10><tr><th class="func">main(w,h)</th></tr><tr><td class="func" data-func="main(w,h)" onmouseup="return pe.jslogo.drop(event,this);"></td></tr></table><br><br>';
  441. pe.jslogo.menu.innerHTML=txt;
  442. pe.jslogo.content.appendChild(pe.jslogo.menu);
  443. pe.jslogo.canvas=document.createElement('canvas');
  444. pe.jslogo.canvas.style='position:absolute;width:100%;height:100%;visibility:hidden;';
  445. pe.jslogo.canvas.onclick=pe.jslogo.main;
  446. pe.jslogo.content.appendChild(pe.jslogo.canvas);
  447. } else {
  448. pe.jslogo.canvas.style.visibility='hidden';
  449. pe.jslogo.menu.style.visibility='visible';
  450. }
  451. },
  452. draw:function() {
  453. window.scrollTo(0,0);
  454. pe.jslogo.clearerr();
  455. pe.jslogo.menu.style.visibility='hidden';
  456. pe.jslogo.canvas.style.visibility='visible';
  457. var ctx = pe.jslogo.canvas.getContext("2d"), w=pe.jslogo.canvas.offsetWidth, h=pe.jslogo.canvas.offsetHeight, tbl=document.getElementById("editor");
  458. pe.jslogo.canvas.width=w; pe.jslogo.canvas.height=h; pe.jslogo.pen=true; pe.jslogo.color='#000000';
  459. ctx.scale(1,1); ctx.clearRect(0,0,w,h); ctx.translate(w/2,h/2); ctx.beginPath(); ctx.moveTo(0,0);
  460. if(!pe.jslogo.interpret(ctx, tbl.rows[1].cells[0],{"w":w,"h":h}))
  461. pe.jslogo.main();
  462. else
  463. if(pe.jslogo.drawturtle) ctx.drawImage(pe.jslogo.turtle,-8,-8);
  464. pe.jslogo.working.style.visibility='hidden';
  465. },
  466. expr:function(str,vars) {
  467. if(str==null||str=='') throw 'Empty expression';
  468. str=str.replace(/[a-z]+/gi,function makevar(s) { if(vars[s]==null) { console.log(str); throw 'No such variable'; } return 'vars[\''+s+'\']'; });
  469. return eval(str);
  470. },
  471. interpret:function(ctx,obj,vars) {
  472. var i,cmd,args,val,err,j;
  473. if(pe.jslogo.debuglog) console.log('Logo INFO: interpret',obj.getAttribute('data-func')?obj.getAttribute('data-func'):'(block)',vars);
  474. if(obj==null||obj.childNodes==null||obj.childNodes.length==0) return true;
  475. try {
  476. for(i=0;i<obj.childNodes.length;i++) {
  477. if(obj.childNodes[i]==null||obj.childNodes[i].firstChild==null) continue;
  478. err=null;
  479. if(obj.childNodes[i].firstChild.tagName=='TABLE') {
  480. err=obj.childNodes[i].firstChild.rows[0].cells[0];
  481. //control structures
  482. cmd=obj.childNodes[i].firstChild.rows[0].cells[0].firstChild.getAttribute('data-cmd');
  483. args=obj.childNodes[i].firstChild.rows[0].cells[0].firstChild.nextSibling.innerHTML.replace(/&gt;/gi,'>').replace(/&lt;/gi,'<').replace(/ and /gi,' && ').replace(/&amp;/gi,'&').replace(/ or /gi,' || ').replace(/=/gi,'==').replace(/>==/gi,'>=').replace(/<==/gi,'<=');
  484. if(args==null||args=='') { throw 'Missing expression'; }
  485. val=Math.round(pe.jslogo.expr(args,vars));
  486. if(pe.jslogo.debuglog) console.log('Logo INFO:',cmd,args,val);
  487. if(cmd=='repeat') {
  488. if(val) for(j=0;j<val;j++) {
  489. vars['repcount']=j;
  490. if(!pe.jslogo.interpret(ctx, obj.childNodes[i].firstChild.rows[1].cells[0], vars)) return false;
  491. }
  492. } else
  493. if(cmd=='if') {
  494. if(!pe.jslogo.interpret(ctx, obj.childNodes[i].firstChild.rows[1].cells[val?0:1], vars)) return false;
  495. } else
  496. throw 'Unknown keyword';
  497. } else if(obj.childNodes[i].firstChild.tagName=='IMG') {
  498. err=obj.childNodes[i];
  499. //command
  500. cmd=obj.childNodes[i].firstChild.getAttribute('data-cmd');
  501. args=obj.childNodes[i].firstChild.nextSibling.innerHTML;
  502. if(cmd!='pendown' && cmd!='penup' && (args==null||args=='')) { throw 'Missing argument'; }
  503. if(pe.jslogo.debuglog) console.log('Logo INFO:',cmd,args);
  504. if(cmd=='pendown') { pe.jslogo.pen=true; } else
  505. if(cmd=='penup') { pe.jslogo.pen=false; } else
  506. if(cmd=='let') {
  507. var v=args.split('=');
  508. if(!v[0].match(/^[a-z]+$/)) throw 'Bad variable';
  509. vars[v[0]]=pe.jslogo.expr(v[1],vars);
  510. } else
  511. if(cmd=='question') {
  512. var v=args.split(','),a;
  513. if(!v[0].match(/^[a-z]+$/)) throw 'Bad variable';
  514. a=prompt(v[2],v[1]);
  515. if(a==null) throw('No input');
  516. vars[v[0]]=a;
  517. } else
  518. if(cmd=='rand') {
  519. var b,v=args.split(',');
  520. if(!v[0].match(/^[a-z]+$/)) throw 'Bad variable';
  521. b=vars[v[0]]; while(b==vars[v[0]]) b=Math.floor(Math.random()*(Math.floor(v[2])-Math.ceil(v[1])))+Math.ceil(v[1]);
  522. vars[v[0]]=b;
  523. } else
  524. if(cmd=='alert') {
  525. alert(args);
  526. } else
  527. if(cmd=='debug') {
  528. var v;
  529. try{v=pe.jslogo.expr(args,vars);}catch(e){v='';};
  530. if(v==args) v='';
  531. console.log('Logo DEBUG:',args,v);
  532. } else
  533. if(cmd=='forward') {
  534. val=pe.jslogo.expr(args,vars);
  535. if(pe.jslogo.pen) { ctx.strokeStyle=pe.jslogo.color; ctx.lineTo(0,-val); ctx.stroke(); }
  536. ctx.translate(0,-val); ctx.beginPath(); ctx.moveTo(0,0);
  537. } else
  538. if(cmd=='backward') {
  539. val=pe.jslogo.expr(args,vars);
  540. if(pe.jslogo.pen) { ctx.strokeStyle=pe.jslogo.color; ctx.lineTo(0,val); ctx.stroke(); }
  541. ctx.translate(0,val); ctx.beginPath(); ctx.moveTo(0,0);
  542. } else
  543. if(cmd=='left') {
  544. val=pe.jslogo.expr(args,vars);
  545. ctx.rotate((360-val)*Math.PI/180.0);
  546. } else
  547. if(cmd=='right') {
  548. val=pe.jslogo.expr(args,vars);
  549. ctx.rotate(val*Math.PI/180.0);
  550. } else
  551. if(cmd=='color') {
  552. pe.jslogo.color=args;
  553. } else
  554. if(cmd=='text') {
  555. var v=args.split(',');
  556. ctx.fillStyle=pe.jslogo.color;
  557. ctx.font=v[0]+'px serif';
  558. ctx.fillText(v[1],0,0);
  559. } else
  560. if(cmd=='call') {
  561. var p=obj.childNodes[i].firstChild.nextSibling.getAttribute('data-pars').trim(), c=Math.round(obj.childNodes[i].firstChild.nextSibling.getAttribute('data-call')), tbl=document.getElementById("editor"), v=args.substr(0,args.length-1).substring(args.indexOf('(')+1,args.length).trim(), j, va=new Array();
  562. if(c<1||c>=tbl.rows[1].cells.length) throw 'Unknown function';
  563. if(p!='') p=p.split(','); else p=[];
  564. if(v!='') v=v.split(','); else v=[];
  565. if(p.length!=v.length) throw 'Arguments mismatch';
  566. for(j=0;j<p.length;j++) va[p[j]]=pe.jslogo.expr(v[j],vars);
  567. if(!pe.jslogo.interpret(ctx, tbl.rows[1].cells[c],va)) return false;
  568. } else
  569. throw 'Unknown command';
  570. }
  571. }
  572. } catch(e) {
  573. console.log('Logo ERROR:',e);
  574. try{err.className+=' error';err.setAttribute('title',L(e.toString()));}catch(e){};
  575. return false;
  576. }
  577. return true;
  578. }
  579. };