פונקציות וביטויים
אין ב-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) בצורה חד-כיוונית: אותו טקסט תמיד ייתן בדיוק אותו קוד, אבל אין שום דרך לקחת את הקוד ולשחזר ממנו את הטקסט המקורי. בדיוק בשביל זה בונים בו בדיקת סיסמה - שומרים רק את הקוד, לא את הסיסמה עצמה.
mode: click
key: {{username}}
fields: [ passwordHash = {{inpw|hash}} ]
mode: click
key: {{username}}
יעד: storedHash (property: passwordHash)
operator: ==
right: storedHash
זה טוב לשער כניסה פשוט באפליקציה קטנה (הזמנות, מועדון לקוחות, איזור צוות). זה לא תחליף למערכת התחברות מאובטחת אמיתית עם שרת ייעודי - אין כאן הגבלת ניסיונות, אימות דו-שלבי, או תעודות 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