Sunday 29th, January 2006
Written By : Lance SpellmanCategory : Lotusphere
This is the 3rd article in the introduction to the Domino Facelift. The first article's here if you need to start from the beginning.
Let's recap:
There are lots of ways to skin this cat. Let's list them:
Number 2 has the same issues as number 1, but with the calls now extracted out into a JS library script.
Number 3 is what we've done with this version of the Facelift. It eliminates the complexity of figuring out which items Domino's actually going to render to the page because Domino's already completed that task. Now, given the elements actually present in the browser, we can call back to the server for the additional design information about those elements. This is accomplished via the script tag added to the bottom of the form.
The agent will read the query string for the form to get the form name to examine. It checks to see if a valid cached document has been created for that form that contains all the DXL to JS conversions. If it has, and the date on the cached doc is more recent than the last time the form design was modified, it sends the contents of the document to the browser. The document contents are the JS calls that add behavior to the design elements (e.g. a date picker). Here's the content of the GetCacheDoc function in the dfl_DynamicForm.js agent in the Facelift database:
For those who want to avoid the agent call, the dynamic script can be eliminated. After you've put this code in place and previewed the form, the cache doc has all the function calls required. Simply remove the call to the dfl_StaticForm.js script on the form. Put the function calls in the JSHeader, and add an onLoad to the body to execute them.
Next articles:
Let's recap:
- we can get the DXL for a form and find more properties to reveal to the browser.
- we can turn that DXL information into a series of javascript calls
- we can create a javascript library of functions that provide implementations for those calls (such as a date picker)
There are lots of ways to skin this cat. Let's list them:
- Trigger some code when the Form is saved in the Designer client and add the calls directly to the form itself
- Trigger some code when the Form is saved in the Designer client and create a custom JS library containing those function calls
- When the form is rendered in the browser, go examine the DXL and dynamically add the function calls to the page
- Write an nsfhook so that the Domino rendering engine finds the additional function calls and dynamically adds them to the page
Number 2 has the same issues as number 1, but with the calls now extracted out into a JS library script.
Number 3 is what we've done with this version of the Facelift. It eliminates the complexity of figuring out which items Domino's actually going to render to the page because Domino's already completed that task. Now, given the elements actually present in the browser, we can call back to the server for the additional design information about those elements. This is accomplished via the script tag added to the bottom of the form.
<script language=javascript src='/facelift/facelift.nsf/dfl_StaticForm.js' /></script>
That .js file is in Script Libraries in the Facelift database. When it executes, it sets a timer event on the web page that waits for the page to finish loading. Then, it grabs the form name, does a little housekeeping and creates a url for calling a LS agent back on the server. Here's that code from the fl_onLoad function of the dfl_StaticForm.js script library.
var src = "/" +g_faceliftDB + "/dfl_dynamicForm.js?OpenAgent&form=" + formName
var fieldsNames = "&"
var EachElement
for (var Count=0; Count
EachElement = frm.elements[Count]
if(fieldsNames.indexOf("," + EachElement.name +":" + EachElement.type + ",")==-1) {
if(EachElement.type!="hidden"){
fieldsNames += EachElement.name +":" + EachElement.type + ","
}
}
}
src += "&Fields=" + escape(fieldsNames.slice(1))
var CustomScript = document.createElement('script');
CustomScript.setAttribute('src', src);
CustomScript.setAttribute("LANGUAGE", "javascript");
CustomScript.setAttribute("type","text/javascript")
document.body.appendChild(CustomScript);
That is a holy hack my friends...using an included js file to create another call for a javascript file on the fly. This is what Dwight calls "dynamic js" and his way around using AJAX. When the last line of that code runs, it will have created a new script tag in the body of the page that will immediately execute and call a LotusScript agent.var fieldsNames = "&"
var EachElement
for (var Count=0; Count
if(fieldsNames.indexOf("," + EachElement.name +":" + EachElement.type + ",")==-1) {
if(EachElement.type!="hidden"){
fieldsNames += EachElement.name +":" + EachElement.type + ","
}
}
}
src += "&Fields=" + escape(fieldsNames.slice(1))
var CustomScript = document.createElement('script');
CustomScript.setAttribute('src', src);
CustomScript.setAttribute("LANGUAGE", "javascript");
CustomScript.setAttribute("type","text/javascript")
document.body.appendChild(CustomScript);
The agent will read the query string for the form to get the form name to examine. It checks to see if a valid cached document has been created for that form that contains all the DXL to JS conversions. If it has, and the date on the cached doc is more recent than the last time the form design was modified, it sends the contents of the document to the browser. The document contents are the JS calls that add behavior to the design elements (e.g. a date picker). Here's the content of the GetCacheDoc function in the dfl_DynamicForm.js agent in the Facelift database:
Set FormLookupView = gcmn_CurrDB.GetView("FormLookup")
Set g_CacheDoc = FormLookupView.GetDocumentByKey( DBPath & "~" & FormName)
If g_CacheDoc Is Nothing Then
Set g_CacheDoc = New notesdocument( gcmn_CurrDB)
g_CacheDoc.Form = "fl_Form"
g_CacheDoc.DBPath = DBPath
g_CacheDoc.FormName = FormName
End If
g_CacheDoc.warnings= ""
Set targetdb = New NotesDatabase( gcmn_currdb.Server, DBPath)
If Not targetdb.IsOpen Then
Call ReportFATALERROR("Unable To Open Database")
End If
Set nc = targetdb.CreateNoteCollection(False)
nc.SelectForms = True
nc.SelectionFormula = |$TITLE = "| & FormName & |"|
Call nc.BuildCollection
If nc.Count = 0 Then
Call ReportFATALERROR("Unable To Find Form")
Elseif nc.count > 1 Then
Call ReportFATALERROR("Found More than one Form")
End If
formNoteid = nc.GetFirstNoteId()
Set FormDoc = TargetDB.GetDocumentByID( FormNoteID)
If FormDoc Is Nothing Then
Call ReportFATALERROR("Unable to retrieve form by noteid")
End If
If Len(g_CacheDoc.SavedXML(0)) = 0 Then
Call ParseNC(NC)
Elseif Getparameter( gcmn_CTXDoc.http_referer(0), "deletecache") = "yes" Then
Call ParseNC(NC)
Elseif isnewer( formdoc, g_CacheDoc) Then
Call ParseNC(NC)
End If
If the cache doc has not been created or is not valid (form design has been updated), then it examines the DXL for the form, performs the DXL to JS convesions, stores them in a cache doc and sends the contents to the browser. This is how the JS calls for additional functionality get attached to the page. Is it a hack, yes. Would it be a problem to call agents in large scale environments? Potentially. How often do users call for forms in edit/open mode?Set g_CacheDoc = FormLookupView.GetDocumentByKey( DBPath & "~" & FormName)
If g_CacheDoc Is Nothing Then
Set g_CacheDoc = New notesdocument( gcmn_CurrDB)
g_CacheDoc.Form = "fl_Form"
g_CacheDoc.DBPath = DBPath
g_CacheDoc.FormName = FormName
End If
g_CacheDoc.warnings= ""
Set targetdb = New NotesDatabase( gcmn_currdb.Server, DBPath)
If Not targetdb.IsOpen Then
Call ReportFATALERROR("Unable To Open Database")
End If
Set nc = targetdb.CreateNoteCollection(False)
nc.SelectForms = True
nc.SelectionFormula = |$TITLE = "| & FormName & |"|
Call nc.BuildCollection
If nc.Count = 0 Then
Call ReportFATALERROR("Unable To Find Form")
Elseif nc.count > 1 Then
Call ReportFATALERROR("Found More than one Form")
End If
formNoteid = nc.GetFirstNoteId()
Set FormDoc = TargetDB.GetDocumentByID( FormNoteID)
If FormDoc Is Nothing Then
Call ReportFATALERROR("Unable to retrieve form by noteid")
End If
If Len(g_CacheDoc.SavedXML(0)) = 0 Then
Call ParseNC(NC)
Elseif Getparameter( gcmn_CTXDoc.http_referer(0), "deletecache") = "yes" Then
Call ParseNC(NC)
Elseif isnewer( formdoc, g_CacheDoc) Then
Call ParseNC(NC)
End If
For those who want to avoid the agent call, the dynamic script can be eliminated. After you've put this code in place and previewed the form, the cache doc has all the function calls required. Simply remove the call to the dfl_StaticForm.js script on the form. Put the function calls in the JSHeader, and add an onLoad to the body to execute them.
Next articles:
- Dwight puts a wizard around "facelifting a form"
- Series on how the View facelift works
- Examining the nsfhooks approach to adding behavior directly through the Domino Web Engine
1. Kary Forth02/13/2006 08:01:03 AM
Homepage: http://www.projectedge.com
Keep the articles coming...
2. Glenn Kohner03/01/2006 09:32:25 AM
Homepage: http://www.vintara.com
I would love to see this important project succeed. Why not use AJAX ? Is there a hosted version of the facelift database ? Are you looking at dojotoolkit?
3. William beh05/19/2006 02:17:34 AM
Homepage: http://notesweb2.blogspot.com/
Can't wait for any prototype of the facelift db.
Any update recently?
4. a11/26/2006 11:25:52 PM
Homepage: http://a
5. 11/26/2006 11:26:16 PM
6. Dwight Wilbanks05/28/2008 01:10:23 PM
Homepage: http://www.dwightwilbanks.org
test
Powered By :
BlogSphere
Join The WebLog Revolution at BlogSphere.net







