לא מזמן התבקשתי לעזור לתכנן אפליקציית אינטרנט בה המסך יכול להיות מחולק לכמה חלקים, והמשתמש יכול לגלוש באותה אפליקצייה מכל חלק - כך שהוא יוכל לראות כמה חלקים שונים של אותה אפליקצייה, באותו מסך.
במידה שהיינו מתחילים לכתוב את האפליקצייה מאפס, כנראה שהיינו בוחרים ב - Single Applcation Page וכל האתר היה עובד ב - ajax, וכך לא היה שום בעיה לחלק את המסך לשניים או יותר חלקים.
הבעייה שהאתר כבר היה כתוב :-)
במקרה הזה לאחר חשיבה הגענו למסקנה שהשיטה הכי יעילה, היא לחלק את העמוד הראשי לכמה iframes שהמשתמש יוכל לנווט בכל חלק מבלי לגרום ל - post back לכל החלקים האחרים.
כאן הגענו לבעייה חדשה, היות שמדובר בטאב אחד - כל ה - iframes חולקים את אותו session, ואין שום דרך בצד השרת לדעת מאיזה חלק הגיע ה - post back, והיות שהרבה מידע עבור המשתמש היה נשמר ב - session - כמו בחירות של תפריטים וכדו', נניח שהמשתמש היה בוחר בחירה מסויימת באחד החלקים, והוא היה הולך לחלק שני ועושה משם post back, השרת היה מתייחס לבחירה של המשתמש מהחלק האחר.
לאחר חצי יום נסיונות כתבתנו את הקוד הבא:
<table>
<tr>
<td><iframe src="WebForm2.aspx" data-side="LeftTop"></iframe></td>
<td><iframe src="WebForm2.aspx" data-side="RightTop"></iframe></td>
</tr>
<tr>
<td><iframe src="WebForm2.aspx" data-side="LeftButtom"></iframe></td>
<td><iframe src="WebForm2.aspx" data-side="RightButtom"></iframe></td>
</tr>
</table>
לכל iframe הוספנו attribute בשם data-side עם ערך שמכיל היכן פיזית הוא יושב בדף (
data הינו תוספת של html5 כך שמאפיינים שאינם בתקן יוכלו להתווסף לאלמנטים)
כעת כל iframe מכיל את המידע היכן הוא יושב, כעת נשאר למצוא דרך לספר את זה לשרת, מבלי צורך לשנות את כל הקוד הקיים, גילינו שכל הדפים שה - iframe מצביע אליהם משתמשים באותו master page, הוספנו את הקוד הבא:
<script>
$(window).bind('beforeunload', function () {
$(parent.document).find('iframe').each(function (index, value) {
if (value.contentWindow == window) {
var side = $(value).attr('data-side');
$.cookie('side', side);
}
});
});
</script>
נרשמנו לאירוע
beforeunload שיקרה כל פעם לפני כל post back ולפני עזיבת העמוד (על ידי לינק לדף אחר וכד'), נמצא את העמוד שמכיל את כל ה - iframes בעזרת הפיכת ה - document של ה - parent לאובייקט jquery, נחפש את כל ה - ifrmae ונרוץ עליהם בלולאה.
נבדוק האם החלון שנמצא בתוך ה - ifrmae הוא אכן החלון שלנו (החלון שמתוכו מתבצע ה - post back)
במידה וכן, נוציא את הערך שנמצא במאפיין data-side (ניסינו בהתחלה להשתמש בפונקציית data של jquery בצורה הבאה:
var side = $(value).data('side');
הבעייה שלאחר מספר post back איכשהו לא קבלנו את המידע הנכון - ולכן חזרנו ל - attr הישן והטוב)
כעת שמרנו את הערך ב - cookie בשם side (היות שבכל request כל ה - cookies נשלחים לשרת).
בצד השרת הגדרנו enum שנראה כך:
public enum Side
{
LeftTop,
RightTop,
LeftButtom,
RightButtom
}
בקוד הוספנו ב - page_load (של מחלקת ה - PageBase - המחלקה שכל הדפים בפרוייקט יורשים מהם) את הקוד הבא:
HttpCookie sideCookie = Request.Cookies["side"];
if (sideCookie != null)
{
Side side = (Side)Enum.Parse(typeof(Side), sideCookie.Value);
}
כעת ניתן היה לשאול בכל מקום בקוד מהיכן נעשה ה - post back. (ספציפית שם בפרוייקט הוספנו מנגנון שכל שמירה ב - Session תעבור דרך פונקצייה שמשתמשת ב - side כדי לשמור את ה - session לאותו side (כלומר הוספנו את ה - ToString של המשתנה side לשם ה - session) כך שניתן תמיד להוציא את המידע הרלוונטי לאותו side)
אחרי קצת דיבגינג גילינו שחלק מה - post back לא מגיעים לקוד ה - beforeunload, בדיקה קטנה גילתה שמדובר ב - post back מתוך update panel, מה שגרם לנו להוסיף את הקוד הבא:
<script>
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_beginRequest(function (requestManager, args) {
saveSideInCookie();
});
</script>
כמובן שהוצאנו את הקוד מלמעלה לפונקצייה שנקראת saveSideInCookie, חשוב בנוסף לשים לב שהסקריפט הזה צריך לשבת אחרי ההגדרה של ה - Script Manager.
הקוד הזה יגרום לכך שכל async post back ישמור את המידע ב - cookie.