במאמר זה נסביר כיצד להוסיף הודעה נפתחת, איך עושים חלוקה לעמודים וגם על טופס הוספת ההודעה. כמו כן נסביר על הקפצות ונעיצות.
כיוון שפורום רקורסיבי זולל משאבי שרת אז נתחיל בכך שנעביר את הפקודות הבסיסיות שלנו לצד הלקוח. אבל קודם כל נעביר את הרשומות לצד הלקוח ע"י השיטה getString
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
<% dim query, rs, strRecArray, cntFields, oConn Set oConn=Server.CreateObject("ADODB.connection") oConn.Open "Provider=microsoft.jet.oledb.4.0; data source="&Server.mapPath("db/forum.mdb")&";" query = "SELECT forum.id, forum.parentId, forum.subject FROM forum ORDER BY forum.id" SET rs = Server.CreateObject("ADODB.Recordset") rs.Open query, oConn cntFields = rs.fields.count ' count of fields that we selected strRecArray = rs.getString(2,-1, ",", ",") rs.Close Set rs = Nothing %> <script type="text/javascript"> var recArray = "<% =strRecArray %>" recArray = recArray.substr(0, (recArray.length-1)) recArray = recArray.split(",") /// Now we have array with one dimension of records var cntFields = new Number(<% =cntFields %>); for (var i=0;i<recArray.length;i+=cntFields){ if (recArray[i+1]==0){ showMessage(i); document.write("<hr />") } }
function showMessage(index){ var subject = new String(recArray[index+2]); document.write("<div style="padding–right: 20px">"); document.write(subject); document.write("<hr />"); for (var a=0;a<recArray.length;a+=cntFields){ if (recArray[a+1]==recArray[index]) showMessage(a); } document.write("</div>"); }
</script>
|
|
|
למה דווקא getString ?
getString זו שיטה שמחזירה לנו את כל הרשומות כמחרוזת אחת לעומת getRows שמחזירה לנו את כל הרשומות כמערך (חד מימדי או דו מימדי, תלוי בשפה). ולכן כאשר אנו מעבירים את הרשומות מהלקוח לשרת אז העברת מחרוזת יעשה יותר מהר כי העברת מערך דורשת מאיתנו לבצע לולאה בשרת שז"א עוד פעולות שעושים על השרת = אפליקציה פחות מהירה.
כדי להבין את השיטה שבה אנחנו נעבוד עם הרשומות ששלפנו רצוי מאוד לקרוא את המאמר " עבודה עם getRows ב-JS צד שרת " , למרות שהמאמר מסביר על צד שרת אנחנו עובדים באותה דרך: מערך חד מימדי שכל איבר מכיל שדה ואין קבוצה של שדות כרשומה (כמו ב-VBS/ASP צד שרת). – קריאה נעימה.
לאחר שהעברנו את כל הפעולות שלנו לצד הלקוח נתחיל בעבודה. עד עכשיו יש לנו רק נושאים בפורום ועכשיו הגיע הזמן להוסיף הודעות לכן אנו צריכים גם להוסיף במסד שלנו עמודת הודעות נקרא לעמודה של message (מקורי מאוד) ולכן ככה צריכה להיראות הטבלה שלנו במסד:
ID |
מספור אוטומטי |
מפתח ראשי |
parentId |
מספר |
ID של הודעת האב-הודעה ראשית תהיה 0 |
Subject |
טקסט |
נושא ההודעה – סימון כחובה required |
message |
תזכיר – Memo |
ההודעה |
לאחר שהוספנו את העמודה לטבלה עלינו לשלוף אותה. אז עכשיו השאילתא שלנו נראית ככה:
|
query = "SELECT forum.id, forum.parentId, forum.subject, forum.message FROM forum ORDER BY forum.id"
|
|
|
פתיחת הודעות באותו עמוד
לאחר ששלפנו את ההודעות עלינו להדפיס אותם בדף ב-div נסתר (כדי ליצור אפקט הודעה נפתחת) עם ID ייחודי לכל הודעה (ה-ID יהיה מילה עם ה-ID של הרשומה) לכן הפוקנציה שלנו צריכה להיות כך:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
function showMessage(index){ var subject = new String(recArray[index+2]); document.write("<div style="padding-right: 20px">"); document.write("<span >") document.write(subject); document.write("</span>") document.write("<div style="display:none;" id="mess_" + recArray[index] + "" >"); document.write(recArray[index+3] + "<br />"); document.write("<a href="addMess.asp?id=" + recArray[index] + "&rootId=" + recArray[index+4] + "" >הוסף תגובה</a>") document.write("</div><hr />"); for (var a=0;a<recArray.length;a+=cntFields){ if (recArray[a+1]==recArray[index]) showMessage(a); } document.write("</div>"); }
|
|
|
עכשיו כדי ליצור את אפקט ההודעה הנפתחת נכתוב פונקציה נפרדת שמקבלת את ה-ID של האלמנט ופותחת סוגרת בהתאם
|
function displayMessage(id){ var obj = documentgetElementById(id); obj.style.display=(obj.style.display=="block"?"none":"block"); }
|
|
|
ועכשיו נגרום לכך שברגע שילחצו על הנושא אז ההודעה תיפתח
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
function showMessage(index){ var subject = new String(recArray[index+2]); document.write("<div style="padding-right: 20px">"); /* —> */document.write("<span onclick=" displayMessage(mess_" + recArray[index] + ")" >") document.write(subject); document.write("</span>") document.write("<div style="display:none;" id="mess_" + recArray[index] + "" >"); document.write(recArray[index+3]); document.write("<a href="addMess.asp?id="" + recArray[index] + "&rootId=" + recArray[index+4] + "" >הוסף תגובה</a>") // [index+4] is the field rootId that we create continue
document.write("</div>"); for (var a=o;a<recArray.length;a+=cntFields){ if (recArray[a+1]==recArray[index+1]) showMessage(a); } }
|
|
|
וכאן סיימנו לעשות את ההודעה הנפתחת.
חלוקה לעמודים
לרוב אנו משתמשים ב-ADO כדי לעשות חלוקה לעמודים אבל אצלנו גם ההודעות וגם התגובות נמצאות באותה טבלה אז שיטה זו לא תעזור לנו כי השיטה הזו תפצל לנו שרשורים ולכן יהיו תגובות שלעולם לא נראה. לפני שנעשה את החלוקה לעמודים עצמה נוסיף לנו הודעה בטבלה בשם rootId תפקידה לשייך כל הודעה/תגובה לשרשור המקורי שלה עמודה זו תהיה מסוג מספר. הטבלה שלנו עכשיו נראית כך :
ID |
מספור אוטומטי |
מפתח ראשי |
parentId |
מספר |
ID של הודעת האב-הודעה ראשית תהיה 0 |
Subject |
טקסט |
נושא ההודעה – סימון כחובה required |
message |
תזכיר – Memo |
ההודעה |
rootId |
מספר שלם |
ה-ID של ההודעה הראשית |
msgDate |
תאריך/שעה |
תאריך כתיבת ההודעה (ערך ברירת מחדל now()) |
לאחר שהוספנו את העמודה נוסיף view שירכז לנו רק את ה-rootIdים שאנו צריכים View – שאילתא שנעשית במסד (לא ברמת ה-ASP) ומאפשרת לשמור נתונים מסוימים לעצמנו.
את ה-view באקסס אנו יוצרים בכך שאנו נכנסים לקטגורייה queries ושם אנו בוחרים ב-"צור שאילתא בתצוגת עיצוב". לאחר שאנו יודעים מה זה view בואו ניצור אותו. אנו ניכנס לאפשרות של כתיבת SQL ונכתוב את השאילתא הבאה (נקרא ל-view שלנו fixedForum ) :
|
SELECT forum.rootID, Max(forum.rootID) AS MAXrootID, Max(forum.msgDate) AS MAXmsgDate FROM forum GROUP BY forum.rootID |
|
|
השאילתא הזו תחזיר לנו את כל ה-rootId הקיימים בטבלה שלנו.
עכשיו החלוקה לעמודים מתבצעת כך:
עמוד ראשון – 15 ההודעות הראשונות
עמוד שני – 15 ההודעות הראשונות שאחרי 15 ההודעות הראשונות
עמוד שלישי – 15 ההודעות הראשונות אחרי 30 ההודעות הראשונות
וכך הלאה…
עכשיו איך אנו מבצעים זאת? בעזרת ה-view ואופרטור in אנו נשלוף את כל ההודעות שה-rootId שלהם נמצא בין ה-15 הראשונים.
|
SELECT forum.id, forum.parentId, forum.subject, forum.message FROM forum WHERE forum.rootId in (SELECT TOP 15 fixedForum.rootId FROM fixedForum ORDER BY fixedForum.MAXmsgDate DESC) ORDER BY forum.id |
|
|
אבל השאילתא הזו מתאימה אך ורק לעמוד הראשון בעמוד השני והלאה נצטרך לעשות עוד תת שאילתא שנשתמש בה עם שילוב האופרטורים not in
|
SELECT forum.id, forum.parentId, forum.subject, forum.message FROM forum WHERE forum.rootId in (SELECT TOP 15 fixedForum.rootId FROM fixedForum WHERE fixedForum.rootId not in( SELECT TOP (15 *x) fixedForum.rootId FROM fixedForum ORDER BY fixedForum.MAXmsgDate) ORDER BY fixedForum. MAXmsgDate DESC ) ORDER BY forum.id DESC
|
|
|
X הוא משתנה חיצוני המסמל את מספר העמוד בו אנחנו נמצאים עכשיו כדי לעשות דפדוף בתיבת select אנו צריכים לעשות שליפה חדשה (שליפה נוספת).
בשליפה אנו נשלוף את המס' הכללי של השרשורים בעזרת הפונקציה count .לאחר מכן נכניס לתוך משתנה את מס' השרשורים שיש בעמוד (לפי בחירה) ולאחר מכן ניצור משתנה בשם pageCount שיכיל את התוצאה של פעילת החילוק הבאה : מס' השורשים הכללי חלקיי מס' השרשורים בעמוד בעצם המשתנה pageCount בודק עד לכמה עמודים נעשה החילוק.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
<% paggingQuery = "SELECT COUNT(fixedForum.rootID) as total FROM fixedForum" Set rs1 = Server.CreateObject("ADODB.Recordset") rs1.Open paggingQuery, oConn cntRec = cint(rs1.fields("total")) rs1.Close set rs1 = nothing %> <select name="NextPre" onChange="location.href='forum.asp?id='+NextPre.value"> <script type="text/javascript"> var total, recForPage, pageCount total = Math.round(<%=cntRec %>) recForPage = 15 pageCount = Math.round(total/recForPage) if (pageCount<=0) pageCount=1; if (pageCount<(total/recForPage)) pageCount++; for (var i=1;i<=pageCount;i++) document.write("<option value=""+i+"">"+i+"</option>"); </script> </select>
|
|
|
לבינתיים ככה נראה הקוד שלנו :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
|
<html dir="rtl"><% dim query, rs, strRecArray, cntFields, x, subSubQuery, subQuery, id x = cInt(Request.QueryString("pageid")-1)
if len(request.queryString("ID"))=0 then x=0 else x = cint(cint(request.queryString("id"))-1) end if
subSubQuery = " SELECT TOP "&(15 *x)&" fixedForum.rootId FROM fixedForum ORDER BY fixedForum.MaxmsgDate)"
if x<=0 then subQuery = "SELECT TOP 15 fixedForum.rootID FROM fixedForum ORDER BY fixedForum.rootID DESC, fixedForum.MaxmsgDate DESC" else subQuery = "SELECT TOP 15 fixedForum.rootID FROM fixedForum WHERE rootID not in (" & subSubQuery & ") ORDER BY fixedForum.rootID DESC, fixedForum.MaxmsgDate DESC" END if
query ="SELECT forum.id, forum.parentId, forum.subjet,forum.message,forum.rootId" & _ " FROM forum" &_ " WHERE forum.rootId in ("&subQuery&")" &_ " ORDER BY forum.id"
Set oConn=Server.CreateObject("ADODB.connection") oConn.Open "Provider=microsoft.jet.oledb.4.0; data source="&Server.mapPath("db/forum.mdb")&";" query ="SELECT forum.id, forum.parentId, forum.subject,forum.message,forum.rootId" & _ " FROM forum" &_ " WHERE forum.rootId in ("&subQuery&")" &_ " ORDER BY forum.id" SET rs = Server.CreateObject("ADODB.Recordset") rs.Open query, oConn cntFields = rs.fields.count ' count of fields that we selected strRecArray = rs.getString(2,-1, ",", ",") rs.Close Set rs = Nothing %> <script type="text/javascript"> var recArray = "<% =strRecArray %>" recArray = recArray.substr(0, (recArray.length-1)) recArray = recArray.split(",") /// Now we have array with one dimension of records var cntFields = new Number(<% =cntFields %>); for (var i=0;i<recArray.length;i+=cntFields){ if (recArray[i+1]==0){ showMessage(i); } }
function displayMessage(id){ var obj = document.getElementById(id); obj.style.display=(obj.style.display=="block"?"none":"block"); }
function showMessage(index){ var subject = new String(recArray[index+2]); document.write("<div style="padding–right: 20px">"); document.write("<span onclick=" displayMessage('mess_" + recArray[index] + "')" >") document.write(subject); document.write("</span>") document.write("<div style="display:none;" id="mess_" + recArray[index] + "" >"); document.write(recArray[index+3] + "<br />"); document.write("<a href="addMess.asp?id=" + recArray[index] + "&rootId=" + recArray[index+4] + "" >הוסף תגובה</a>") document.write("</div><hr />"); for (var a=0;a<recArray.length;a+=cntFields){ if (recArray[a+1]==recArray[index]) showMessage(a); } document.write("</div>"); }
</script>
<br /><br /><br /> <% paggingQuery = "SELECT COUNT(fixedForum.rootID) as total FROM fixedForum" Set rs1 = Server.CreateObject("ADODB.Recordset") rs1.Open paggingQuery, oConn cntRec = cint(rs1.fields("total")) rs1.Close set rs1 = nothing %> <select name="NextPre" onChange="location.href='forum.asp?id='+NextPre.value"> <script type="text/javascript"> var total, recForPage, pageCount total = Math.round(<% =cntRec %>) recForPage = 15 pageCount = Math.round(total/recForPage) if (pageCount<=0) pageCount=1; for (var i=1;i<=pageCount;i++) document.write("<option value=""+i+"">"+i+"</option>"); </script> </select> </html>
<% oConn.Close set oConn=Nothing %>
|
|
|
הקפצות ונעיצות
כל הרעיון הוא שלכל הודעות האב אתה מצמיד עוד שדה לפיו אתה מסדר את סדר ההודעות.
בעת תגובה לשרשור כלשהו אתה מגיע לשדה הזה של הודעת האב של השרשור ומעדכן בה את הערך לזמן הנוכחי, ככה כאשר הפורום יהיה מסודר לפי השדה הזה (לצורך העניין נקרא לו groupDate) יהיו לך הודעות מסודרות לפי הזמן האחרון לתגובה לשרשורים המלאים.
נעיצת הודעות גם עובדת באמצעות השדה הזה. את ההקפצה תתנה בכך שהשדה groupDate קטן מהזמן הנוכחי. אם אתה רוצה לנעוץ שרשור קבע את ערך השדה groupDate לרגע הנעיצה פלוס שלושה ימים (לדוגמה). כך שרשור נעוץ לא יאבד את הנעיצה שלו על-ידי "הקפצה" (שתגרום לפעולה הפוכה), והסידור לפי השדה groupDate עדיין יישמר.
ולכן הטבלה שלנו תראה כך עכשיו :
ID |
מספור אוטומטי |
מפתח ראשי |
parentId |
מספר |
ID של הודעת האב-הודעה ראשית תהיה 0 |
Subject |
טקסט |
נושא ההודעה – סימון כחובה required |
message |
תזכיר – Memo |
ההודעה |
rootId |
מספר שלם |
ה-ID של ההודעה הראשית |
msgDate |
תאריך/שעה |
תאריך כתיבת ההודעה (ערך ברירת מחדל now()) |
groupDate |
תאריך/שעה |
תאריך ההקפצה האחרונה או תאריך סיום הנעיצה |
ועכשיו אנו רק נוסיף בפסוקית ה-ORDER BY את השדה – groupDate וזהו יש לנו הקפצות ונעיצות.
|
<% query = "SELECT forum.id, forum.parentId, forum.subjet, forum.message, forum.rootId" & _ " FROM forum" &_ "WHERE forum.rootId in ("&subQuery&")" &_ " ORDER BY forum.id, foum.groupDate" %> |
|
|
עמוד הוספת ההודעה/תגובה
עכשיו אנו ניצור את עמוד הטופס addMess.asp . זה יהיה טופס HTML פשוט הכולל: נושא, הודעה ושני inputים נסתרים המכילים את ה-ID של ההודעה אליה אנו מגיבים(ה-parentId) ואת ה-rootId של השרשור (את שני הערכים אנו שולחים ב-queryString) :
|
<html> <head><title>הוספת הודעה</title></head> <body> <form action="insMessage.asp" method="post"> נושא: <input type="text" name="subject" /><br> ההודעה:<br> <textarea name="message"></textarea><br> <input type="hidden" name="parentId" value="<% =Request.QueryString("id") %>" /> <input type="hidden" name="rootId" value="<% =Request.QueryString("rootId") %>" /> <input type="submit" value=" שלח " /> </form> </body> </html>
|
|
|
לאחר שיצרנו את הטופס עלינו ליצור גם את העמוד שיכניס לנו את הנתונים למסד. לעמוד קוראים InsMessage.asp והוא ישתמש בפקודת ה-INSERT של ה-SQL כדי להכניס את הנתונים למסד.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
<% Dim subject, message, parentId, rootId, oConn Set oConn = Server.CreateObject("ADODB.Connection") oConn.Open "Provider=microsoft.jet.oledb.4.0;Data Source=" & Server.MapPath("../db/ourSongDb.mdb") & ";" subject = Request.Form("subject") message = Request.Form("message") parentId = Request.Form("parentId") rootId = Request.Form("rootId")
if (parentId="") Then ' אם להכניס הודעה או תגובה insertNewMess 0,subject,message else insertNewRess parentId,subject,message, rootId End If
Sub insertNewMess (pId, subject, mess) ' פונקציה להכנסת הודעה חדשה Dim rs, SQLinsert, SQLUpdate oCon.BeginTrans SQLinsert = "INSERT INTO forum (parentid, subject, message,groupDate)" SQLinsert = SQLinsert & " VALUES (" & pId & ",'" & subject & "','" & mess & "',now())" oConn.Execute SQLinsert Set rs = Server.CreateObject("ADODB.Recordset") rs.Open "SELECT MAX(id) FROM forum",oConn oCon.CommitTrans SQLUpdate = "UPDATE forum SET forum.rootId=" & rs(0) & " WHERE forum.id=" & rs(0) oConn.Execute SQLUpdate rs.Close Set rs = nothing End Sub
Sub insertNewRess(pId, subject, mess, rId)' פונקציה להכנסת תגובה חדשה Dim SQLupdate, SQLinsert, rs, dt, rsDt SQLinsert = "INSERT INTO forum (parentid, subject, message, rootId)" SQLinsert = SQLinsert & " Values(" & pId & ",'" & subject & "','" & mess & "'," & rId & ")" oConn.Execute SQLinsert Set rs = Server.CreateObject("ADODB.Recordset") rs.Open "SELECT forum.groupDate FROM forum WHERE forum.id=" & rId, oConn dt = Now() rsDt = CDate(rs.Fields("groupDate")) if (rsDt<=dt) Then ' בדיקה האם ההודעה הראשית(הודעת השרשור) נעוצה או לא SQLupdate = "UPDATE forum SET forum.groupDate=now() WHERE forum.id=" & rId oConn.Execute SQLupdate End If rs.Close Set rs = nothing End Sub
oConn.Close Set oConn = nothing Response.Redirect("index.asp") ' להחזיר לעמוד הצגת ההודעות %>
|
|
|
חשוב לציין שלהוספת הודעה חדשה עלינו לשלוח parentID עם הערך 0
ולהוספת תגובה עלינו לשלוח parentId שיהיה שווה ל-ID של ההודעה אליה אנו מגיבים וגם את ה-rootId של ההודעה אחרת היא לא תוצג וגם לא תיעשה הקפצה.
וזהו סיימנו את המאמר. תכנות נעים :
תגובות בפייסבוק