אפליקציות של Blockly יוצרות לעיתים קרובות JavaScript כשפת הפלט שלהן, בדרך כלל כדי להפעיל אותה בתוך דף אינטרנט (יכול להיות אותו דף או WebView מוטמע). כמו בכל מחולל, השלב הראשון הוא לכלול את מחולל ה-JavaScript.
import {javascriptGenerator} from 'blockly/javascript';
כדי ליצור JavaScript מסביבת העבודה, קוראים לפונקציה:
javascriptGenerator.addReservedWords('code');
var code = javascriptGenerator.workspaceToCode(workspace);
אפשר להריץ את הקוד שמתקבל ישירות בדף האינטרנט של היעד:
try {
eval(code);
} catch (e) {
alert(e);
}
בגדול, קטע הקוד שלמעלה פשוט יוצר את הקוד ומבצע הערכה שלו. עם זאת, יש כמה שיפורים. שיפור אחד הוא שהפונקציה eval עטופה ב-try
/catch
כדי ששגיאות זמן ריצה יהיו גלויות, במקום להיכשל בשקט. שיפור נוסף הוא הוספת code
לרשימת המילים השמורות, כך שאם הקוד של המשתמש מכיל משתנה עם השם הזה, הוא ישונה אוטומטית במקום ליצור התנגשות. צריך לשמור משתנים מקומיים בדרך הזו.
הדגשת בלוקים
הדגשת הבלוק שמופעל כרגע בזמן שהקוד פועל עוזרת למשתמשים להבין את ההתנהגות של התוכנית שלהם. אפשר להדגיש כל הצהרה בנפרד על ידי הגדרת STATEMENT_PREFIX
לפני יצירת קוד ה-JavaScript:
javascriptGenerator.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
javascriptGenerator.addReservedWords('highlightBlock');
מגדירים את highlightBlock
כדי לסמן את הבלוק בסביבת העבודה.
function highlightBlock(id) {
workspace.highlightBlock(id);
}
כתוצאה מכך, ההצהרה highlightBlock('123');
נוספת לפני כל הצהרה, כאשר 123
הוא המספר הסידורי של הבלוק שמודגש.
לולאות אינסופיות
למרות שהקוד שמתקבל תמיד נכון מבחינת התחביר, הוא עשוי להכיל לולאות אינסופיות. פתרון בעיית העצירה חורג מהיכולות של Blockly (!), ולכן הדרך הכי טובה להתמודד עם המקרים האלה היא להשתמש במונה ולהקטין אותו בכל פעם שמתבצעת איטרציה.
כדי לעשות את זה, פשוט מגדירים את javascriptGenerator.INFINITE_LOOP_TRAP
לקטע קוד שיוכנס לכל לולאה ולכל פונקציה. לדוגמה:
window.LoopTrap = 1000;
javascriptGenerator.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = javascriptGenerator.workspaceToCode(workspace);
דוגמה
הדגמה פעילה של יצירה והרצה של JavaScript.
JS-Interpreter
אם חשוב לכם להפעיל את החסימות של המשתמשים בצורה תקינה, כדאי להשתמש בפרויקט JS-Interpreter. הפרויקט הזה נפרד מ-Blockly, אבל הוא נכתב במיוחד בשביל Blockly.
- הפעלת קוד בכל מהירות.
- השהיה/המשך/ביצוע שלב אחר שלב.
- הדגשת בלוקים בזמן ההרצה.
- מבודד לחלוטין מ-JavaScript בדפדפן.
הפעלת תרגום שיחה פעילה
קודם כול, מורידים את JS-Interpreter מ-GitHub:
לאחר מכן מוסיפים אותו לדף:
<script src="acorn_interpreter.js"></script>
הדרך הפשוטה ביותר להפעיל אותו היא ליצור את ה-JavaScript, ליצור את המפענח ולהריץ את הקוד:
var code = javascriptGenerator.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();
הזזת המתורגמן
כדי להריץ את הקוד לאט יותר או בצורה מבוקרת יותר, מחליפים את הקריאה ל-run
בלולאה שמבצעת צעד אחד (במקרה הזה, צעד אחד כל 10 אלפיות השנייה):
function nextStep() {
if (myInterpreter.step()) {
setTimeout(nextStep, 10);
}
}
nextStep();
חשוב לזכור שכל שלב הוא לא שורה או בלוק, אלא יחידה סמנטית ב-JavaScript, שיכולה להיות מאוד מפורטת.
הוספת API
JS-Interpreter הוא ארגז חול שמבודד לחלוטין מהדפדפן. כל בלוק שמבצע פעולות עם העולם החיצוני דורש הוספה של API למתורגמן. תיאור מלא זמין במסמכי התיעוד של JS-Interpreter. אבל כדי להתחיל, הנה ה-API שנדרש לתמיכה בבלוקים של התראות והנחיות:
function initApi(interpreter, globalObject) {
// Add an API function for the alert() block.
var wrapper = function(text) {
return alert(arguments.length ? text : '');
};
interpreter.setProperty(globalObject, 'alert',
interpreter.createNativeFunction(wrapper));
// Add an API function for the prompt() block.
wrapper = function(text) {
return prompt(text);
};
interpreter.setProperty(globalObject, 'prompt',
interpreter.createNativeFunction(wrapper));
}
לאחר מכן משנים את האתחול של המפענח כדי להעביר את הפונקציה initApi:
var myInterpreter = new Interpreter(code, initApi);
הבלוקים של ההתראה וההנחיה הם שני הבלוקים היחידים בקבוצת הבלוקים שמוגדרת כברירת מחדל שדורשים API בהתאמה אישית עבור המפענח.
מתבצע חיבור אל highlightBlock()
כשמריצים את highlightBlock()
ב-JS-Interpreter, צריך להריץ אותו באופן מיידי, מחוץ לארגז החול, כשהמשתמש עובר על התוכנית. כדי לעשות את זה, יוצרים פונקציית wrapper highlightBlock()
כדי לתעד את הארגומנט של הפונקציה, ורושמים אותה כפונקציה מקורית.
function initApi(interpreter, globalObject) {
// Add an API function for highlighting blocks.
var wrapper = function(id) {
return workspace.highlightBlock(id);
};
interpreter.setProperty(globalObject, 'highlightBlock',
interpreter.createNativeFunction(wrapper));
}
אפליקציות מתוחכמות יותר עשויות להריץ שוב ושוב שלבים בלי הפסקה עד שמגיעים לפקודת הדגשה, ואז להשהות את הפעולה. האסטרטגיה הזו מדמה ביצוע שורה אחר שורה. בדוגמה הבאה מוצג השימוש בגישה הזו.
דוגמה ל-JS-Interpreter
בסרטון ההדגמה הזה מוסבר איך לפרש JavaScript שלב אחר שלב. הדמו הזה כולל בלוק המתנה, דוגמה טובה לשימוש בהתנהגות אסינכרונית אחרת (למשל, דיבור או אודיו, קלט משתמש).