ספר ההדרכה / פונקציות וביטויים

פונקציות וביטויים

אין ב-AppNoy ספריית "פונקציות" בסגנון UPPER() או DATE(). במקום זה יש שפת ביטויים קטנה ומדויקת שמבוססת כולה על התחביר {{...}}, כולל פילטרים שאפשר לשרשר, ופילטרים ייעודיים לסיסמאות ולהצפנה.

א. הצבת משתנים בטקסט

כל שדה טקסט (טקסט של רכיב, הודעת toast, קישור וכו׳) יכול להכיל {{name}} שיוחלף בערך בזמן ריצה. הפירוש נעשה לפי הסדר: קודם "טוקנים של מערכת" (ראו הטבלה הבאה), אחר-כך משתנים שהוגדרו, ואם שום דבר לא נמצא - מוצג טקסט ריק.

ב. טוקני מערכת

טוקן מחזיר
{{now}} תאריך ושעה נוכחיים, מפורמט לפי השפה
{{today}} תאריך נוכחי בפורמט YYYY-MM-DD
{{epochMs}} מילישניות מאז epoch, כטקסט - נוח למיון כרונולוגי
{{uuid}} מזהה ייחודי בסגנון UUID v4
{{random}} מספר שלם אקראי בין 0 ל־999999
{{genId}} מזהה ארוך וייחודי מבוסס-זמן (מומלץ כשצריך זיהוי אמין)
{{shortId}} קוד קצר בן 3 ספרות (100–999) - נוח להקלדה, אך לא מובטח כייחודי
{{joystickX}} / {{joystickY}} מיקום חי בין 1- ל-1 של רכיב ג'ויסטיק (בונה המשחקים), מתעדכן ברציפות כל עוד הוא מוחזק
{{tiltX}} / {{tiltY}} הטיית מכשיר חיה בין 1- ל-1, לאחר שפעולת "הפעלת בקרת הטיה" רצה
{{lastKey}} המקש (e.key - "Enter", "ArrowUp", אות וכו') שהפעיל לאחרונה אירוע "לחיצה על מקש" - ראו פרק "אירועים"

ג. פילטרים (עם |)

אפשר לצנרר ערך דרך פילטר בכתיב {{name|upper}}. הנה כל הפילטרים הקיימים:

קטגוריה פילטר מה עושה
טקסט בסיסי upper הופך לאותיות גדולות
lower הופך לאותיות קטנות
trim מסיר רווחים מההתחלה והסוף
עיצוב טקסט capitalize הופך רק את האות הראשונה לגדולה
title אות ראשונה גדולה בכל מילה
reverse הופך את סדר התווים
length מספר התווים בטקסט
ניקוי וזיהוי digitsOnly משאיר רק ספרות (נוח לניקוי מספרי טלפון)
slug הופך לכתובת-URL ידידותית: אותיות קטנות ומקפים במקום רווחים/סימנים
mask מסתיר הכל חוץ מ-4 התווים האחרונים (••••1234) - טוב להצגת מידע רגיש בלי לחשוף אותו
מספרים round מעגל למספר שלם
currency מוסיף ₪ ומפריד אלפים, שתי ספרות אחרי הנקודה
percent מוסיף % בסוף
אבטחה ופרטיות hash חד-כיווני - לשמירת סיסמאות, ראו סעיף ד׳ מיד למטה
encrypt הפיך - להצפנת מידע לשמירה, ראו סעיף ה׳ מיד למטה
decrypt הופך encrypt בחזרה לטקסט המקורי

שרשור כמה פילטרים בשדה אחד

אפשר לשרשר כמה פילטרים ברצף על אותו ערך, אחד אחרי השני עם | - כל פילטר מקבל את התוצאה של הפילטר שלפניו:

{{name|trim|lower|capitalize}}

הדוגמה הזו מנקה רווחים מיותרים, הופכת הכל לאותיות קטנות, ואז מעלה רק את האות הראשונה - כך ש-" דני " ו-"DANI" יוצגו באותה צורה עקבית "Dani". אין הגבלה על כמות הפילטרים בשרשרת אחת.

ד. שמירת סיסמאות בלי לשמור את הסיסמה עצמה (hash)

הפילטר hash הופך כל טקסט לקוד ארוך וקבוע (SHA-256) בצורה חד-כיוונית: אותו טקסט תמיד ייתן בדיוק אותו קוד, אבל אין שום דרך לקחת את הקוד ולשחזר ממנו את הטקסט המקורי. בדיוק בשביל זה בונים בו בדיקת סיסמה - שומרים רק את הקוד, לא את הסיסמה עצמה.

דוגמה: הרשמה עם סיסמה, ואז בדיקת התחברות
שני מסכים: הרשמה שומרת רק את ה-hash של הסיסמה; התחברות בודקת אם ה-hash של מה שהוקלד תואם למה שנשמר - הסיסמה עצמה אף פעם לא נשלחת או נשמרת.
אירוע - מסך הרשמה
אינטראקציה עם אלמנט
elementId: btn_signup
mode: click
פעולה
שמירה באחסון השרת (dbSet)
collection: users
key: {{username}}
fields: [ passwordHash = {{inpw|hash}} ]
אירוע - מסך התחברות
אינטראקציה עם אלמנט
elementId: btn_login
mode: click
פעולה
קריאה מאחסון השרת (dbGet)
collection: users
key: {{username}}
יעד: storedHash (property: passwordHash)
תנאי
תנאי
left: inpw|hash
operator: ==
right: storedHash
כן
פעולה
מעבר למסך
screen: home
לא
פעולה
הצגת הודעה
text: "שם משתמש או סיסמה שגויים"
חשוב להבין את הגבולות

זה טוב לשער כניסה פשוט באפליקציה קטנה (הזמנות, מועדון לקוחות, איזור צוות). זה לא תחליף למערכת התחברות מאובטחת אמיתית עם שרת ייעודי - אין כאן הגבלת ניסיונות, אימות דו-שלבי, או תעודות SSL ברמת בנק. אל תשתמשו בזה לנתונים רגישים באמת (כספים, מסמכים משפטיים וכו׳).

ה. הצפנת מידע שצריך לקרוא שוב (encrypt / decrypt)

בניגוד ל-hash, encrypt הפיך: שומרים ערך מוצפן בטבלה, ומתי שצריך להציג אותו שוב - מריצים עליו decrypt וחוזרים בדיוק לטקסט המקורי. שימושי כשרוצים שמידע (הערה פרטית, פרט זיהוי) לא יופיע כטקסט גלוי לכל מי שפותח את עמוד "נתונים" בדשבורד, אבל האפליקציה עצמה עדיין צריכה להציג אותו למשתמש הנכון.

{{sdb.notes[{{userId}}].secret = {{privateNote|encrypt}}}}

ולהצגה חוזרת של אותו ערך על המסך:

{{element[3].text = {{sdb.notes[{{userId}}].secret|decrypt}}}}
זו הצפנה "מסתירה", לא הצפנה ברמה בנקאית

המפתח של ה-encrypt/decrypt קבוע ומוטמע בקוד הציבורי של האפליקציה (אותו קובץ JS שכל מבקר מוריד) - כלומר זה מונע מעיניים סתמיות לראות את הערך (למשל בטבלת הנתונים בדשבורד), אבל לא עומד מול מישהו נחוש שבודק את קוד הדפדפן. לסיסמאות ולכל דבר שבאמת קריטי להגנה - להשתמש ב-hash (חד-כיווני) ולא ב-encrypt.

ו. "הרצת קוד" (מתקדם) - שפת נתיבים מיני

פעולת הרצת קוד היא לא JavaScript אמיתי (לא eval) - זו שפת נתיבים קטנה לקריאה/כתיבה שרצה בתוך בלוקים {{ }}, ותומכת ב:

תחביר משמעות
element[N].prop קריאה/כתיבה לרכיב מספר N במסך הנוכחי בלבד (למשל element[2].text)
db.path.to.value אחסון מקומי במכשיר הזה (נתיב מקווקוו לתוך אובייקט)
sdb.table[key].col שורה בטבלת שרת משותפת - כשמגיעים אליה דרך runCode היא תמיד גלובלית (בשונה מפעולות dbSet/dbGet הייעודיות, שברירת המחדל שלהן פרטית)
myVar מזהה חשוף (בלי נקודות) - משתנה קאש שהוגדר
path = value השמה, למשל {{myVar = 5}}. אפשר לקנן בלוקים זה בתוך זה - הפנימי נפתר קודם
a + b, a - b, a * b, a / b אופרטור אחד בכל פעם (עם רווח משני צידי הסימן) - בלי סדר פעולות ובלי שרשור ("2 + 3 * 4" לא מתחשב כ-14; לקנן בלוקים {{ }} במקום), ואין פונקציות מחרוזת. חילוק באפס מחזיר 0, לא שגיאה. זה כל התמיכה החשבונית בשפה כולה - מספיק למונים, ולחשבון בסיסי למשחקים כמו כבידה/מהירות

דוגמה נפוצה - מונה שעולה ב-1 בכל לחיצה:

{{sdb.scores[id].points = {{sdb.scores[id].points}} + 1}}

ז. ביטויי תנאי

פעולת התנאי הפשוטה ("תנאי") היא רק צד־שמאל / אופרטור / צד־ימין. האופרטורים הזמינים: == שווה ל, != לא שווה ל, > גדול מ, < קטן מ, >=, <=, contains מכיל, empty ריק, notEmpty לא ריק. פירוט מלא בפרק "תנאים".

כשצריך לוגיקה מורכבת יותר יש את "תנאי מורכב (טקסט חופשי)" - דקדוק אמיתי עם AND/OR/NOT וסוגריים, למשל:

(age >= 18 OR vip) AND NOT banned