Devign באנגלית

שייך לקטגוריות Devign

לאחר מספר שנים עם הבלוג בעברית, פתחתי בלוג נוסף באנגלית בכתובת http://devign.me

בנוסף לפוסטים שתורגמו מהבלוג הזה, אפרסם שם פוסטים נוספים, חדשים.

אשמח לשמוע פידבקים בתגובות. תהנו :)

OhBehave – החלת התנהגות על אלמנט סטטי או דינמי בצורה מיידית

שייך לקטגוריות CSS, HTML, JavaScript

באפליקציות ווב ואתרים עשירים, לעיתים קרובות יש צורך בהחלת התנהגות כלשהי על אלמנט.

דוגמאות:

  • הפיכת תיבת select לפקד autocomplete
  • השמת אלמנט בתוך מסגרת מורכבת (פינות מעוגלות, שקיפות)
  • החלת אירועי לחיצה על אלמנטים מסוג מסויים
  • השמת תווית צפה מעל פקד טקסט עד ל-focus/שינוי ערכו

פיתרון סטנדרטי יהיה להמתין לעליית ה-dom (פונקציה אשר מצוייה בכל ספריית js אשר מכבדת את עצמה), לרוץ על אלמנטים עם class מסויים, ולהפעיל פונקציית js שתחיל את ההתנהגות.

שימו לב! במידה ומדובר בהצמדת אירועים בלבד כדאי מאוד להשתמש בשיטת ה-Event Delegation

חסרונות השיטה:

  • לפעמים, לוקח מעט זמן עד שה-dom עולה והאלמנט מופיע בגרסתו נטולת ההתנהגות עד לסיום הטעינה
  • כאשר מוסיפים דינמית אלמנטים לעמוד (innerHTML או createElement & appendChild) צריך לדאוג להחיל את ההתנהגות שוב, על כל האלמנטים שדורשים זאת
  • כפיתרון גנרי לאלמנטים דינמיים אפשר להפעיל טיימר על העמוד שיחקור את ה-dom בכל פעם מחדש. זהו תהליך איטי, וב-delay בקריאות ל-interval עלולות להיות קפיצות

דוגמה לעבודה בשיטה זו:

<script type=”text/javascript”>
function applyBehaviors() {
    var elements=$.select(“.behavior”);
    for (var i=0;i<elements.length;i++) applySpecificBehavior(elements[i]);
}

$.domready(function () {
    applyBehaviors();
});

$.ajax("url.html",
    onSuccess:function () {
        applyBehaviors();
    }
);
</script>

(הפונקציות $.select, $.domready, $.ajax הינן פונקציות פיקטיביות המקנות אפשרות לבחור אלמנטים לפי css selector, לבצע פעולה מייד בעליית ה-dom וביצוע בקשת ajax, בהתאמה. ניתן למצוא אותן בכל ספריית javascript המכבדת את עצמה).

הפיתרון הנכסף – OhBehave

OhBehave הינו סקריפט חביב, שאחראי על החלת התנהגות על אלמנטים באופן מיידי, ברגע הראשון בו הם זמינים. מבלי להמתין לטעינת שאר העמוד. בנוסף, מחיל את ההתנהגות גם על אלמנטים חדשים הנוצרים דינמית.

איך זה עובד?

לכל דפדפן נאלצתי למצוא פיתרון שונה, מאחר וכל אחד מיישם את הפונקציונליות בה רציתי באופן אחר. מתוך כל מנגנון בחרתי להפעיל פונקציה בשם OhBehave.initialize שמקבלת אלמנט ותניע את החלת ההתנהגויות.
התנהגויות האלמנט מוגדרות אף הן ב-class שלו. לדוגמה – oh-behave-WrapWithFrame, oh-behave-Autocomplete (שימו לב לקידומת oh-behave-).
כל התנהגות היא פונקציה המאוחסנת באובייקט OhBehave.behaviors שמקבלת אלמנט עליו היא מחילה התנהגות בודדת.
לא רציתי לכבול לשימוש ב-OhBehave, כך שניתן להגדיר את הפונקציה גם כגלובאלית, ואף ניתן לשנות את קידומת ההתנהגות (ראו בקובץ המצורף).

דוגמה:

OhBehave.behaviors["AlertTheTime"]=function (element) {
    element.onclick=function () {
        alert(new Date());
    };
};

// or -- function AlertTheTime(element) { … }

Firefox ‏ (Gecko Engine) – שימוש ב-XBL

XBL או XML Binding Language היא שפת תגיות מבוססת XML המוגדרת בתקן W3C להחלת התנהגות עשירה לאלמנט. ה-XBL מאפשר להגדיר מאפיינים (כולל getters/setters), אירועים וירייתם, מתודות וקוד CSS/JS שיחול על האלמנט. ה-XBL מוצמד בעזרת css בתצורה:

.oh-behave { -moz-binding:url("oh-behave.xml#oh-behave"); }

ומבנה ה-xml:

<bindings xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml">
    <binding id="oh-behave">
        <implementation>
            <constructor>OhBehave.initialize(this);</constructor>
        </implementation>
    </binding>
</bindings>

כרגע רק מנוע Gecko תומך ב-XBL, על אף שהוא בתקן.
הצמדתי XBL ל-css class מסויים ומתוכו הפעלתי קוד גנרי המחיל התנהגות.

IE ‏ ‏ (Trident Engine) – שימוש ב-HTC

HTC, או HTML Component הינו יישום של Microsoft להחלת התנהגות עשירה לאלמנט. הוא מאפשר פחות או יותר את מה שה-XBL מאפשר.

Safari/Chrome ‏ (WebKit Engine) – האירוע DOMNodeInserted

מאחר וב-WebKit עוד לא הכניסו את XBL לשימוש (בקוד המקור יש אזכורים אך כנראה האופציה עדיין כבוייה), נאלצתי למצוא פיתרון אחר. האירוע DOMNodeInserted (אירוע המוגדר בתקן) נורה כאשר אלמנט מוכנס לעמוד דינמית (innerHTML / createElement & appendChild). דרך אירוע זה אני מחפש את האלמנטים עליהם יש להחיל את ההתנהגות. חיפוש האלמנטים מתבצע בעזרת querySelectorAll – מתודה של אלמנט או מסמך, המקבלת css selector ומגישה את כל האלמנטים העונים על סלקטור זה, תחת אותו אלמנט.
בעליית העמוד השתמשתי באירוע DOMContentLoaded שרץ מייד בעליית ה-dom. כאן עלולה להיות קפיצה קטנה, אבל המנוע כל-כך מהיר שאני לא חושב שיהיה אפשר להבחין בה.

דוגמה חיה

בעמוד הדוגמה ניתן לראות החלת שתי התנהגויות על אלמנט: הראשונה מקיפה אותו במסגרת הכוללת אלמנטים נוספים המרכיבים אותה, השניה מצמידה אירוע לחיצה המציג את הזמן הנוכחי.
בנוסף, כפתור אשר יוצר מוסיף אלמנטים חדשים למסמך בצורה דינמית, וגם עליהם חלות ההתנהגויות, Automagically.

להדגמה של OhBehave

להורדת OhBehave כולל דוגמאות

עברתי לוורדפרס

שייך לקטגוריות Devign

לאחר שנים מספר (קצת יותר מ-3 ליתר דיוק) עם אפליקציית הבלוג הדוטנטית הקודמת – החלטתי לעבור לוורדפרס, בשביל נוחות הכתיבה וכמה דברים בסיסיים שהיו חסרים לי.

כתובת ה-RSS, הודות ל-FeedBurner, נותרה זהה: http://feeds.feedburner.com/Devign

תיתכנה בעיות קלות ב-UI בימים הקרובים.

קריאה נעימה

המתנה אסינכרונית לפעולה ב-JavaScript

שייך לקטגוריות JavaScript

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

סוגי רכיבים נפוצים הם תמונה, קובץ css, קובץ javascript, פניית xmlhttp. לכל אחד מאלה יש אירוע בו אנו יודעים כי הוא נטען, אך עצם העובדה שהוא נטען לא אומרת שהוא התחיל להשפיע על העמוד שלנו.

לדוגמה:

  • טעינה בזמן ריצה של קובץ css והשמתו על העמוד לא אומרת שמיידית הוא ישפיע על האלמנטים.
  • קבלת html מתוך xmlhttp והשמתו על העמוד לא אומרת שמיידית כולו רונדר וניתן לגשת לרכיבים בו ללא בעיה
  • טעינת קובץ javascript לעמוד לא אומרת שכל האובייקטים בו מוכנים לשימוש

לשם מצבי קצה אלו כתבתי פונקציה פשוטה בבסיסה, שממתינה עד אשר פעולה כלשהי בוצעה ורק אז מריצה קוד נוסף.

/// $waitUntil
///		waits until a certain function returns true and then executes a code. checks the function periodically
/// parameters
///		check - a function that should return false or true
///		onComplete - a function to execute when the check function returns true
///		delay - time in milliseconds, specifies the time period between each check. default value is 100
///		timeout - time in milliseconds, specifies how long to wait and check the check function before giving up
function $waitUntil(check,onComplete,delay,timeout) {
	// if the check returns true, execute onComplete immediately
	if (check()) {
		onComplete();
		return;
	}

	if (!delay) delay=100;

	var timeoutPointer;
	var intervalPointer=setInterval(function () {
		if (!check()) return; // if check didn't return true, means we need another check in the next interval

		// if the check returned true, means we're done here. clear the interval and the timeout and execute onComplete
		clearInterval(intervalPointer);
		if (timeoutPointer) clearTimeout(timeoutPointer);
		onComplete();
	},delay);
	// if after timeout milliseconds function doesn't return true, abort
	if (timeout) timeoutPointer=setTimeout(function () {
		clearInterval(intervalPointer);
	},timeout);
}

POC:

var globalVariable=0;

setTimeout(function () { globalVariable=1; },2000);

$waitUntil(
	function () {
		console.log("checking globalVariable="+globalVariable);
		return globalVariable==1;
	},
	function () {
		alert("done!");
	}
);

בדוגמה אנו יכולים לראות שיש משתנה בשם globalVariableשמאותחל ל-0, ולאחר 2 שניות ערכו הופך ל-1 ידנית. הפונקציה $waitUntil מקבלת שתי פונקציות. האחת תחזיר true/false לפי בדיקה שתבצע, והשניה תבצע קוד שירוץ רק אחרי שהראשונה החזירה true.

* הפונקציה console.log שייכת ל-firebug/webkit/ie8 ולא נתמכת ב-ie6/7.

דוגמאות לשימושים יותר נפוצים:

ajax("url.htm",function (source) {
	element.innerHTML=source;
	$waitUntil(
		function () { return document.getElementById("some-id-in-source")!=null; },
		function () { /* source is rendered and #some-id-in-source is available */ }
	);
});

loadCss("file.css",function () {
	$waitUntil(
		function () { return element.offsetHeight>0; },
		function () { /* css is applied on this element */ }
	);
});

loadJs("file.js",function () {
	$waitUntil(
		function () { return typeof(SomeTypeInFileJs)!="undefined"; },
		function () { /* SomeTypeInFileJs is ready to use */ }
	);
});

הפונקציות loadCss, ajax ו-loadJs טוענות אסינכרונית קבצים ומודיעות כשהם נטענו. ניתן למצוא מימוש שלהן בכל ספריית JavaScript המכבדת את עצמה.



קטגוריות

חיפוש

עיקבו אחרי (אקספרימנטלי!)