I'm finally trying out what Jake probably have done for close to four years. Getting rid of "Use JavaScript when generating pages".
My addendum, is the choice of the submit element. In his article he chose <input type="submit" />. The downside with this is that the value attribute is used as a label for the button. I'm going to use <button type="submit">, which frees me to put whatever I want as a label. It makes it a lot easier to make internationalized button, as it lets you separate data from design.
E.g. (brackets indicates field)
<button type="submit" name="action" value="save">[cfd_save_label]</button>
<button type="submit" name="action" value="archive">[cfd_archive_label]</button>
<button type="submit" name="action" value="delete">[cfd_delete_label]</button>
He's probably using this already, but since I couldn't find a mention of it on his site, I thought I should share it with you.
If you're having trouble designing buttons across browsers, check out this guide.
Showing posts with label web. Show all posts
Showing posts with label web. Show all posts
Friday, July 3, 2009
Wednesday, July 1, 2009
HttpRequest class - Support for multivalue requests (e.g. checkbox)
A colleague of mine needed to process values from a form with checkboxes. In some instances, the amount of checked boxes (select all) was so great that he hit the 32k limit of Domino fields.
I suggested that he tried posting to an agent/used my HttpRequest class. This didn't work, as each checkboxvalue is sendt as a single parameter.
E.g. ...make_report?OpenAgent&user=tom&user=jane&user=jack
The previous version of the class only fetched the last parameter.
I updated the code, so that the class aggregates the values into acomma separated string dynamic array. Single value parameters are still Strings.
>> The class in a txt-file
Share and enjoy!
I suggested that he tried posting to an agent/used my HttpRequest class. This didn't work, as each checkboxvalue is sendt as a single parameter.
E.g. ...make_report?OpenAgent&user=tom&user=jane&user=jack
The previous version of the class only fetched the last parameter.
Dim request As New HttpRequest()
Print request.parameter("user")
' Prints jack
I updated the code, so that the class aggregates the values into a
Dim request As New HttpRequest()
Print Join( request.parameter("user"), "," )
' Prints tom,jane,jack
>> The class in a txt-file
Share and enjoy!
Labels:
web
Friday, June 12, 2009
Serving correct MIME-types for Office 2007 attachments on the web
Several of our users had problems with opening Office 2007-attachments in Internet Explorer. The browser identified the attachments as zip files.
The workaround for this is to set up the Domino server to send the appropriate MIME-type header.
The correct headers
Then you need to configure the Domino Server. We hoped it would be as easy as adding config documents to the "File Identifications" view. Alas, this didn't work.
What did work was modifying the httpd file in the data-directory of the server/refreshing http
(tell http refresh).
Not sure if it is a bug that the "File Identifications" solution didn't work..? The server-version is Domino 8.5.
The workaround for this is to set up the Domino server to send the appropriate MIME-type header.
The correct headers
Then you need to configure the Domino Server. We hoped it would be as easy as adding config documents to the "File Identifications" view. Alas, this didn't work.
What did work was modifying the httpd file in the data-directory of the server/refreshing http
(tell http refresh).
# Office 2007
AddType .docm application/vnd.ms-word.document.macroEnabled.12
AddType .docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
AddType .dotm application/vnd.ms-word.template.macroEnabled.12
AddType .dotx application/vnd.openxmlformats-officedocument.wordprocessingml.template
AddType .potm application/vnd.ms-powerpoint.template.macroEnabled.12
AddType .potx application/vnd.openxmlformats-officedocument.presentationml.template
AddType .ppam application/vnd.ms-powerpoint.addin.macroEnabled.12
AddType .ppsm application/vnd.ms-powerpoint.slideshow.macroEnabled.12
AddType .ppsx application/vnd.openxmlformats-officedocument.presentationml.slideshow
AddType .pptm application/vnd.ms-powerpoint.presentation.macroEnabled.12
AddType .pptx application/vnd.openxmlformats-officedocument.presentationml.presentation
AddType .xlam application/vnd.ms-excel.addin.macroEnabled.12
AddType .xlsb application/vnd.ms-excel.sheet.binary.macroEnabled.12
AddType .xlsm application/vnd.ms-excel.sheet.macroEnabled.12
AddType .xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
AddType .xltm application/vnd.ms-excel.template.macroEnabled.12
AddType .xltx application/vnd.openxmlformats-officedocument.spreadsheetml.template
Not sure if it is a bug that the "File Identifications" solution didn't work..? The server-version is Domino 8.5.
Thursday, June 4, 2009
UserCss: Cleaning up the Google Reader interface
I finally had enough with Bloglines. The RSS-robots are extremely slow, the page has a fair amount of downtime, the site has a lot of problems, etc.
I started using Google Reader today. The only thing I didn't like about it was all the clutter. Bloglines wastes little space.
I've known about the posibility for site-specific CSS in Opera for several years, but never had the need for it. This was the perfect occasion to try it out. I used Opera Dragonfly to identify the spots that needed to go/the items that needed to be moved.
This is the result:

(Screenshot from Opera 10 Beta1. Looking forward to being able to have the thumbnails on the left. Not usable as is.)
The stylesheet if you're interested.
In Opera, you're only able to set site-specific CSS per domain. Therefore the above CSS influences all google sites. Opera only stylesheet that doesn't affect (from what little I've tested) other google sites.
I started using Google Reader today. The only thing I didn't like about it was all the clutter. Bloglines wastes little space.
I've known about the posibility for site-specific CSS in Opera for several years, but never had the need for it. This was the perfect occasion to try it out. I used Opera Dragonfly to identify the spots that needed to go/the items that needed to be moved.
This is the result:

(Screenshot from Opera 10 Beta1. Looking forward to being able to have the thumbnails on the left. Not usable as is.)
The stylesheet if you're interested.
In Opera, you're only able to set site-specific CSS per domain. Therefore the above CSS influences all google sites. Opera only stylesheet that doesn't affect (from what little I've tested) other google sites.
Labels:
random tip,
web
Wednesday, April 1, 2009
Updated the TextToPNG-generator
Update 14.04.09: I added support for PNG transparency, and improved the vertical positioning of text to avoid clipping.
When I first made it, i called it a header-generator.
I actually needed something similar today at work, for a newsletter-application I'm working on. I added some functionality at work, and planned to release the updated version as is. I saw how horrendous the interface looked/wished for a little more functionality, so I added a little more functionality/freshened up the interface.
Old interface:

New interface:

>> Download DemoApp
Requirements to run the app: Domino 8.x (code written in Java 5)
Example images:




When I first made it, i called it a header-generator.
I actually needed something similar today at work, for a newsletter-application I'm working on. I added some functionality at work, and planned to release the updated version as is. I saw how horrendous the interface looked/wished for a little more functionality, so I added a little more functionality/freshened up the interface.
Old interface:
New interface:

>> Download DemoApp
Requirements to run the app: Domino 8.x (code written in Java 5)
Example images:





Wednesday, October 15, 2008
High performance readable conditional templates
My search for the perfect templating solution for webapps seems to be neverending.
In my latest concoction, I feel I've got a decent mix between readability, speed and flexibility.
It started out with my feeling that using "readable lookup columns" was a bit to verbose/data-heavy for templating.
I like pipe-separated column values, but on their own, in a template, they can be hard to read.
E.g.
What I want to write is something like this:
In the demoapp I'm currently working on, I pick the field-labels (e.g. $name) from the first line in the lookup-column (fields := ...) using the Formula-property of NotesColumn.
This way, I don't have to maintain documentation of the indexes of the different values, nor the position of the values.
To get the most performance out of the rendering-engine, one more or less has to use evaluated formula-code. Iterating over an array of column-values using Forall/Replace is slower. It's more and more noticable the more documents/values one is putting through the rendering engine. If it's slow with one user, it's going to get a lot slower with hundred users/etc.
If all you were rendering were static content, and have a decent caching-engine, performance per render would be less of a problem.
My current solution is to join the array of column-values to a formula-interpretable-list. Due to Evaluate's limit on length of returned data, I have to process the data in snippets.
E.g. LS-array:
All the templates are "compiled" to @ReplaceSubstring. You can see how I compile/process the templates and data when the demoapp is complete.
Another downside to using pure LS-processing of templates is that it's hard to do conditional templating without slowing down the rendering-engine/writing a lot of code.
Since all data are being processed by Evaluate/Formula, it's quite easy to add conditional compiling as well (@If condition -> conditionalTemplate ). If you want, you can use one template for all the data, or you can have multiple conditions, and a default template.
Example-code from an agent printing a table from 499 documents
Result - odd/even-template
Result - mixed conditional template
At the bottom of the above HTML-files, you can see the amount of values/rendering-time. The time includes all processing, getting field-indexes, columnvalues, rendering, etc. The processing is done on localhost, on my laptop (Core 2 Duo 2GHz/2GB RAM) in Windows XP.
I'm not done yet with the implementation. The current engine is comprised of two classes. One that renders arrays of pipe-separated values (could also process CSV-files), and a subclass that processes the columnvalues of a view.
I plan to add another subclass to the first. This would let you use ft-search on a view, and sort the resulting columnvalues on a field/value in the resulting columnvalues.
If you have further suggestions/wishes/are curious about the code, contact me. Preferably throught comments. :)
I can't say when the demoapp is complete. I'll probably have another update or two before the app is ready for the masses.
In my latest concoction, I feel I've got a decent mix between readability, speed and flexibility.
Readability
It started out with my feeling that using "readable lookup columns" was a bit to verbose/data-heavy for templating.
I like pipe-separated column values, but on their own, in a template, they can be hard to read.
E.g.
template = "<tr><td>$1</td><td>$2</td></tr>"
What I want to write is something like this:
template = "<tr><td>$name</td><td>$address</td></tr>"
In the demoapp I'm currently working on, I pick the field-labels (e.g. $name) from the first line in the lookup-column (fields := ...) using the Formula-property of NotesColumn.
fields := "firstName" : "lastName" : "company" : "address";
@Implode( @Transform( fields ; "fieldname" ;
@Text( @GetField( fieldname ) ) ) ; "|" )
This way, I don't have to maintain documentation of the indexes of the different values, nor the position of the values.
Performance
To get the most performance out of the rendering-engine, one more or less has to use evaluated formula-code. Iterating over an array of column-values using Forall/Replace is slower. It's more and more noticable the more documents/values one is putting through the rendering engine. If it's slow with one user, it's going to get a lot slower with hundred users/etc.
If all you were rendering were static content, and have a decent caching-engine, performance per render would be less of a problem.
My current solution is to join the array of column-values to a formula-interpretable-list. Due to Evaluate's limit on length of returned data, I have to process the data in snippets.
E.g. LS-array:
array = ["Party","Hard"] '(brackets to indicate an array)
formulaListString = |"| + Join( array, |":"| ) + |"|
'result: "Party":"Hard"
All the templates are "compiled" to @ReplaceSubstring. You can see how I compile/process the templates and data when the demoapp is complete.
Flexibility
Another downside to using pure LS-processing of templates is that it's hard to do conditional templating without slowing down the rendering-engine/writing a lot of code.
Since all data are being processed by Evaluate/Formula, it's quite easy to add conditional compiling as well (@If condition -> conditionalTemplate ). If you want, you can use one template for all the data, or you can have multiple conditions, and a default template.
Example-code/results
Example-code from an agent printing a table from 499 documents
Result - odd/even-template
Result - mixed conditional template
At the bottom of the above HTML-files, you can see the amount of values/rendering-time. The time includes all processing, getting field-indexes, columnvalues, rendering, etc. The processing is done on localhost, on my laptop (Core 2 Duo 2GHz/2GB RAM) in Windows XP.
I'm not done yet with the implementation. The current engine is comprised of two classes. One that renders arrays of pipe-separated values (could also process CSV-files), and a subclass that processes the columnvalues of a view.
I plan to add another subclass to the first. This would let you use ft-search on a view, and sort the resulting columnvalues on a field/value in the resulting columnvalues.
If you have further suggestions/wishes/are curious about the code, contact me. Preferably throught comments. :)
I can't say when the demoapp is complete. I'll probably have another update or two before the app is ready for the masses.
Labels:
templating,
web
Thursday, September 25, 2008
The HttpRequest class updated - Get cookie values
I've updated the HTTPRequest-class so that you also can use it to pick cookies of a request.
Example code:
Although I link to Jake's excellent demonstration of how simple it is to get the session cookie, I wrote the cookie-bit a couple of days before, in work relation.
>> HttpRequest Source code
Example code:
Dim request As New HttpRequest()
Dim sessionCookie As String
sessionCookie = request.cookie( "DomAuthSessId" )
Print "I've got your cookie!"
Although I link to Jake's excellent demonstration of how simple it is to get the session cookie, I wrote the cookie-bit a couple of days before, in work relation.
>> HttpRequest Source code
Labels:
domino,
lotusscript,
web
Tuesday, September 23, 2008
Templating: Generating HTML from document collections
Sometimes it can be useful to render HTML from document collections. I believe one of the fastest ways to get values from Notes documents is using Evaluate. As a lazy person, I like to avoid writing formula code, as it's somewhat verbose compared to modern templating languages like PHP.
To avoid this, make your own template interpreter using simple formula code.
Example:
Result: "Date: " + @Text( dayOfMonth) + ". " + month + "."
The result can be used in an evaluate statement.
A great thing about templating is that it is very maintainable/reusable. If you want to change the output, all you have to change is the template-string. To generate XML and HTML from the same collection, all you have to do is to have two different string templates. The conversion logic can be the same.
In the simple demoapp I've included, a collection of 300 documents is processed, extracting five fields. A HTML table row is generated per document. class="even"/class="odd" is added so that one can style odd/even rows. If you're somewhat familiar with LotusScript, it should not be hard to make a template-class to fit your needs.
On localhost (my laptop) it takes about 100 milliseconds to generate the HTML/write it to a PassTruHTML NotesRichTextItem.
>> Demoapp
If you want a sorted collection, you can use NotesView.AllEntries, and use NotesViewEntry.Document, to get to the document. Beware of categorized views. Test NotesViewEntry.isValid = True to be certain that the entry represents a NotesDocument. There may be other problems with using NotesViewEntry.Document as well. Proceed with caution/good error handling. :)
To avoid this, make your own template interpreter using simple formula code.
Example:
str := "Date: $#dayOfMonth#$. $?month?$.";
'"' + @ReplaceSubstring( str ;
"$?" : "?$" : "$#" : "#$" ;
'" + ' : ' + "' : '" + @Text( ' : ') + "'
) + '"'
Result: "Date: " + @Text( dayOfMonth) + ". " + month + "."
The result can be used in an evaluate statement.
A great thing about templating is that it is very maintainable/reusable. If you want to change the output, all you have to change is the template-string. To generate XML and HTML from the same collection, all you have to do is to have two different string templates. The conversion logic can be the same.
In the simple demoapp I've included, a collection of 300 documents is processed, extracting five fields. A HTML table row is generated per document. class="even"/class="odd" is added so that one can style odd/even rows. If you're somewhat familiar with LotusScript, it should not be hard to make a template-class to fit your needs.
On localhost (my laptop) it takes about 100 milliseconds to generate the HTML/write it to a PassTruHTML NotesRichTextItem.
>> Demoapp
If you want a sorted collection, you can use NotesView.AllEntries, and use NotesViewEntry.Document, to get to the document. Beware of categorized views. Test NotesViewEntry.isValid = True to be certain that the entry represents a NotesDocument. There may be other problems with using NotesViewEntry.Document as well. Proceed with caution/good error handling. :)
Labels:
domino,
templating,
web
?OpenField - get HTML from a RichText-item
In case you missed it in Yellowcast, episode five. There's an undocumented feature in Lotus Domino that lets you pull HTML from a RichText field. This is a very useful feature for me at least.
Example url: http://www.notes.net/secrets/undocumented.nsf/documentation/easteregg?OpenField
I believe Carl Tyler was one of the first to blog about this.
Why not document such a great feature? Why, IBM?!
Example url: http://www.notes.net/secrets/undocumented.nsf/documentation/easteregg?OpenField
I believe Carl Tyler was one of the first to blog about this.
Why not document such a great feature? Why, IBM?!
Wednesday, September 17, 2008
Json-search on Domino views
Domino (at least pre 8.5) doesn't let you use $$SearchTemplate forms as anything other than vanilla Domino-generated html forms.
This makes it somewhat difficult to search/getting Json-data in return.
The simplest workaround I've found is to make a view with one column. The data is formatted as Json, with a trailing comma. In the search-template, I wrap the $$ViewBody-field like this:
<div id="result">[|$$ViewBody-field|,""]</div>
When I want to search, I use a temporary iframe, added to the DOM using Javascript. To make it as simple as possible, browser compatibility-wise (events), I add a the iframe inside a temporary div using innerHTML. The iframe has an onload-event. When that triggers, I know that the Json is loaded.
I'm terrible at explaining code (terrible at explaining anything), so I've made a simple demo-app you can try. Remember to create a full-text index on the demo-db before trying it out.
Flash demonstration of the app (I parse the Json to HTML):
>> Demoapp
The app is tested, and works in Opera 9.5, FF3 and IE7 on Vista x64.
This makes it somewhat difficult to search/getting Json-data in return.
The simplest workaround I've found is to make a view with one column. The data is formatted as Json, with a trailing comma. In the search-template, I wrap the $$ViewBody-field like this:
<div id="result">[|$$ViewBody-field|,""]</div>
When I want to search, I use a temporary iframe, added to the DOM using Javascript. To make it as simple as possible, browser compatibility-wise (events), I add a the iframe inside a temporary div using innerHTML. The iframe has an onload-event. When that triggers, I know that the Json is loaded.
I'm terrible at explaining code (terrible at explaining anything), so I've made a simple demo-app you can try. Remember to create a full-text index on the demo-db before trying it out.
Flash demonstration of the app (I parse the Json to HTML):
>> Demoapp
The app is tested, and works in Opera 9.5, FF3 and IE7 on Vista x64.
Labels:
domino,
JavaScript,
sntt,
web
Friday, June 13, 2008
Slick integration between FCKeditor and Lotus Domino
Update 16.08.08: According to a commenter, Sinisa, the notes.ini modification is not needed (tested on Domino R7), so even less requirements.. :)
Before you read on. The integration requires you to set DominoDisableFileUploadChecks=1 in notes.ini on the Domino Server.
I found no satisfying integration-examples that included upload-support for FCKeditor, so I decided to try to make the integration myself. As far as I've tested, you can upload whatever you want, only limited by settings in FCK and Domino restrictions.
Flash animation of the integration in action. Shows upload of an image and upload of a flash game.
Although it was a bit hard to hack around Domino restrictions regarding uploading files, I finally found out how to make it work.
All that was needed was a bit of try, fail, retry, repeat, a simple upload-form and a little bit of Javascript.
>> Download
The interesting bits are the fckconfig.js page, the demo form, and the fckupload form. Read Ferdy's article to understand how you can upload files to Domino without using a Domino generated File Upload Control.
Requirements for the demoapp:
fckeditor in [Notes/Domino-path]\data\domino\html\js\fckeditor
If you're not running the demo on localhost, DominoDisableFileUploadChecks=1 in notes.ini on the server.
I found no satisfying integration-examples that included upload-support for FCKeditor, so I decided to try to make the integration myself. As far as I've tested, you can upload whatever you want, only limited by settings in FCK and Domino restrictions.
Flash animation of the integration in action. Shows upload of an image and upload of a flash game.
Although it was a bit hard to hack around Domino restrictions regarding uploading files, I finally found out how to make it work.
All that was needed was a bit of try, fail, retry, repeat, a simple upload-form and a little bit of Javascript.
Demo application
>> Download
The interesting bits are the fckconfig.js page, the demo form, and the fckupload form. Read Ferdy's article to understand how you can upload files to Domino without using a Domino generated File Upload Control.
Requirements for the demoapp:
fckeditor in [Notes/Domino-path]\data\domino\html\js\fckeditor
Tested with FCKeditor 2.6.1 in FF2.0, IE7(Vista) and Opera 9.5 (go try it out).
Labels:
domino,
Show-n-Tell Thursday,
web
Friday, May 30, 2008
A couple of handy cheat sheets
I use both of these on a regular basis. I've printed them out on paper, so they're always withing arms reach.
Domino URL cheat sheet
Domino supported syntax for Full Text searching
For web development, ILoveJackDaniels.com has a few nice ones (the site seems to be down at the moment).
Domino URL cheat sheet
Domino supported syntax for Full Text searching
For web development, ILoveJackDaniels.com has a few nice ones (the site seems to be down at the moment).
Labels:
domino,
random tip,
web
Thursday, May 8, 2008
@Unique in Javascript
Update, 16.06.09: As Ronaldo points out, this doesn't work in IE6, as it doesn't have the Array.indexOf-method (I probably tested the function in a Prototype JS-enviroment). To make the function work for browsers that doesn't have the aforementioned method:
Tested in IE6/FF2
if(!Array.indexOf){
Array.prototype.indexOf = function(obj){
for( var i = 0, len = this.length; i < len; i++){
if(this[i]==obj){
return i;
}
}
return -1;
}
}
function arrayUnique( array ){
var uniqueArray = [];
var item;
for( var i = 0, len=array.length ; i < len ; i++ ){
item = array[i];
if( uniqueArray.indexOf( item ) == -1 ){
uniqueArray.push( item );
}
}
return uniqueArray;
}
Tested in IE6/FF2
Labels:
JavaScript,
web
Friday, April 25, 2008
Setting charset in pages/forms with content-type: text/javascript
The Character set-setting for a page/form doesn't seem to do anything more than to set the character encoding for the text if content-type is text/javascript.
With character set set to Unicode (UTF-8), and content-type to text/javascript, Norwegian letters look like this:

If I set content-type to: text/javascript; charset=utf-8


Much better.. :)
With character set set to Unicode (UTF-8), and content-type to text/javascript, Norwegian letters look like this:

If I set content-type to: text/javascript; charset=utf-8


Much better.. :)
Labels:
domino,
random tip,
web
Wednesday, April 2, 2008
A small simplification to "lookups" on the web
In this post, I referred to a method of looking up one document in a view, using the parameters startkey and untilkey.
E.g.
I discovered today (wonder why it took so long) that the good old count-parameter works just as well as the untilkey-parameter. Personally, I think that the count-parameter is more readable than the previous method.
Simplified url:
I don't know if there is a performance-difference between the two methods. I tried a couple of benchmarks in firebug, but got nothing conclusive.
E.g.
http://server/db.nsf/view?openview
&startkey=alex
&untilkey=alex_
I discovered today (wonder why it took so long) that the good old count-parameter works just as well as the untilkey-parameter. Personally, I think that the count-parameter is more readable than the previous method.
Simplified url:
http://server/db.nsf/view?openview
&startkey=alex
&count=1
I don't know if there is a performance-difference between the two methods. I tried a couple of benchmarks in firebug, but got nothing conclusive.
Labels:
domino,
random tip,
web
Tuesday, March 25, 2008
Improved HttpRequest class - Handles request_content above 64k
For those of you that haven't heard, in Domino 7.01, IBM implemented a workaround for (HTTP POST) request-content above 64k.
I've updated the HttpRequest class, so that it handles requests above 64k automagically.
>> My testbed for the class
The test-app has a page that posts ~260k of data to an agent. This results in 4 request_content fields. The agent prints a report of the request ( [HtppRequest].printHtmlReport ).
The class (txt-file)
Let me know if there are errors.
I've updated the HttpRequest class, so that it handles requests above 64k automagically.
>> My testbed for the class
The test-app has a page that posts ~260k of data to an agent. This results in 4 request_content fields. The agent prints a report of the request ( [HtppRequest].printHtmlReport ).
The class (txt-file)
Let me know if there are errors.
Wednesday, March 5, 2008
Gzipping/serving gzipped static content (JS/CSS)
Bandwidth is still a concern for a big part of the web users. To save bandwidth, the simplest job is to compress the content that "never" changes. For instance JS-frameworks.
There are a couple of approaches to this, "packing" utilities like Dean Edward's packer. This compresses the JS in such a way that it's still "compilable" in it's raw form. Another way is to gzip the file. This requires that the browser unpacks the file before it is sendt to the JS "compiler".
I prefer to use both packed and gzipped JS frameworks in production. This guide will hopefully help you serve gzipped JS-files without too much hassle.
The JS-lib I use in the accompanying demo, MooTools is 72KB "unzipped" (the version that is packed using JsMin). Gzipped, it's just shy of 20KB.
To enable gzipped content on the server, create a web site rule (requires restart of the HTTP-task).
Example of rule:

The above rule works like this: For all files in a subfolder named gz, the domino-server will add a HTTP-header, Content-Encoding, with the value of gzip. This tells the browser that the content it is downloading is compressed.
At Compendia, where I currently work, we've set this as a global rule, as it doesn't affect any other content.
To compress files on your machine, you need an application that can gzip files. I use gzip for DOS.
Download gzip for DOS:
32-bit (doesn't work on 64-bit Vista)
64-bit
Extract the downloaded utility to a folder of your choice. At work, I have it on c:\gzip.
Copy the file(s) you want to compress into the folder you extracted the gzip-utility.
Open command-line. cd into the folder you've extracted the gzipping-utility.
For the 64-bit utility: minigz64 name_of_file.js
For the 32-bit utility: gzip name_of_file.js
Be aware of that the dos application overwrites the original file by default.
Add the uncompressed/compressed file (New File Resource) to the DB of your choice. Rename the uncompressed file to lib\[filename].js, and the compressed to gz\[filename].js
With the aforementioned web site rule in place, browsers opening the gzipped file will get the correct HTTP-header, indicating gzipped content.
Some proxies/browsers/thin clients doesn't support/allow gzipped content. It's easy to identify if a browser supports gzipped content:
In the index-page of the simple demo-app, I compute the folder in a script-tag by the presence of Accept-Encoding: gzip header.
>> Download demo-app with gzip for Dos/mootools compressed/uncompressed.
PS! The index-page needs to run on a server with gzipping enabled, like in the picture at the top of this post. Either that, or you can run the browser in HTTP 1.0-mode. HTTP 1.0 doesn't have the Accept-Encoding header.
Good luck!
There are a couple of approaches to this, "packing" utilities like Dean Edward's packer. This compresses the JS in such a way that it's still "compilable" in it's raw form. Another way is to gzip the file. This requires that the browser unpacks the file before it is sendt to the JS "compiler".
I prefer to use both packed and gzipped JS frameworks in production. This guide will hopefully help you serve gzipped JS-files without too much hassle.
The JS-lib I use in the accompanying demo, MooTools is 72KB "unzipped" (the version that is packed using JsMin). Gzipped, it's just shy of 20KB.
Preparing the Domino server
To enable gzipped content on the server, create a web site rule (requires restart of the HTTP-task).
Example of rule:
The above rule works like this: For all files in a subfolder named gz, the domino-server will add a HTTP-header, Content-Encoding, with the value of gzip. This tells the browser that the content it is downloading is compressed.
At Compendia, where I currently work, we've set this as a global rule, as it doesn't affect any other content.
Compressing files
To compress files on your machine, you need an application that can gzip files. I use gzip for DOS.
Download gzip for DOS:
32-bit (doesn't work on 64-bit Vista)
64-bit
Extract the downloaded utility to a folder of your choice. At work, I have it on c:\gzip.
Copy the file(s) you want to compress into the folder you extracted the gzip-utility.
Open command-line. cd into the folder you've extracted the gzipping-utility.
For the 64-bit utility: minigz64 name_of_file.js
For the 32-bit utility: gzip name_of_file.js
Be aware of that the dos application overwrites the original file by default.
Adding the files to a DB
Add the uncompressed/compressed file (New File Resource) to the DB of your choice. Rename the uncompressed file to lib\[filename].js, and the compressed to gz\[filename].js
With the aforementioned web site rule in place, browsers opening the gzipped file will get the correct HTTP-header, indicating gzipped content.
What about users that doesn't have gzip-enabled browsers/etc?
Some proxies/browsers/thin clients doesn't support/allow gzipped content. It's easy to identify if a browser supports gzipped content:
supportsGzip := ( @Contains( @GetHTTPHeader( "Accept-Encoding" ) ; "gzip" ) );
In the index-page of the simple demo-app, I compute the folder in a script-tag by the presence of Accept-Encoding: gzip header.
"<script src=\"/" + @WebDbName + "/" +
@If( supportsGzip ; "gz" ; "lib" ) + "/mootools-release-1.11.js\"></script>"
>> Download demo-app with gzip for Dos/mootools compressed/uncompressed.
PS! The index-page needs to run on a server with gzipping enabled, like in the picture at the top of this post. Either that, or you can run the browser in HTTP 1.0-mode. HTTP 1.0 doesn't have the Accept-Encoding header.
Good luck!
Labels:
fgoto,
random tip,
web
Monday, February 18, 2008
XML Nodetype Constants
Update, 04.03.08: It appears I was fooled by Prototype. The Node-interface/object is not available in IE.
From reading JS-code in different places, it doesn't look like many people are aware that there are constants for the different node-types in a HTML/XML-document.
Most code I've come over tests the type like this:
if( xmlNode.nodeType == 1 )
Which is ok, if you remember that 1 corresponds with element-nodes. The Node-interface in DOM level 1 contains a property/constant for each of the nodetypes.
A list of the constants:
ELEMENT_NODE: 1
ATTRIBUTE_NODE: 2
TEXT_NODE: 3
CDATA_SECTION_NODE: 4
ENTITY_REFERENCE_NODE: 5
ENTITY_NODE: 6
PROCESSING_INSTRUCTION_NODE: 7
COMMENT_NODE: 8
DOCUMENT_NODE: 9
DOCUMENT_TYPE_NODE: 10
DOCUMENT_FRAGMENT_NODE: 11
NOTATION_NODE: 12
A more readable version to the previous test:
if( xmlNode.nodeType === Node.ELEMENT_NODE )
..if (!window.Node) var Node = { };
if (!Node.ELEMENT_NODE) {
// DOM level 2 ECMAScript Language Binding
Object.extend(Node, {
ELEMENT_NO..
From reading JS-code in different places, it doesn't look like many people are aware that there are constants for the different node-types in a HTML/XML-document.
Most code I've come over tests the type like this:
if( xmlNode.nodeType == 1 )
Which is ok, if you remember that 1 corresponds with element-nodes. The Node-interface in DOM level 1 contains a property/constant for each of the nodetypes.
A list of the constants:
ELEMENT_NODE: 1
ATTRIBUTE_NODE: 2
TEXT_NODE: 3
CDATA_SECTION_NODE: 4
ENTITY_REFERENCE_NODE: 5
ENTITY_NODE: 6
PROCESSING_INSTRUCTION_NODE: 7
COMMENT_NODE: 8
DOCUMENT_NODE: 9
DOCUMENT_TYPE_NODE: 10
DOCUMENT_FRAGMENT_NODE: 11
NOTATION_NODE: 12
A more readable version to the previous test:
if( xmlNode.nodeType === Node.ELEMENT_NODE )
Labels:
fgoto,
JavaScript,
random tip,
web
Wednesday, January 30, 2008
Embed multiple standalone forms on a domino form using DHTML
By standalone I mean that when you submit a form, you don't submit all the others/the main form.
I decided to make this when I read a question in Jake's latest article, How to Embed a Login Form on All Lotus Domino Pages.
The question is not directly connected to this blogpost, but somewhat.
The question:
Hi Jake,
We are getting two HTML form tag in view source of page in browser, one form tag for main form and other which is login form.
My question is, How will I handle when we are submiiting the Login form ? Will it submit the main form as well ?
Could you please help me
Regards
Ajay B Mali
The demoapp loads another form using an iframe. Using DHTML I pick the form out of the iframe and inject it at the top or bottom of the form that is open. The reason for either top or bottom is that forms can't be nested (read Jake's excellent article for more info). If you want it in a specific position on the page, CSS may help you.
The reason for iframe and not XHR (Ajax), is that XHR returns text. With the iframe, I can more or less pick what I want out of the "iframed" document, the way I would on the "main" document.
>> The demoapp (Names-form)
Tested in Opera 9, IE7 (Vista) and Firefox 2
I decided to make this when I read a question in Jake's latest article, How to Embed a Login Form on All Lotus Domino Pages.
The question is not directly connected to this blogpost, but somewhat.
The question:
Hi Jake,
We are getting two HTML form tag in view source of page in browser, one form tag for main form and other which is login form.
My question is, How will I handle when we are submiiting the Login form ? Will it submit the main form as well ?
Could you please help me
Regards
Ajay B Mali
The demoapp loads another form using an iframe. Using DHTML I pick the form out of the iframe and inject it at the top or bottom of the form that is open. The reason for either top or bottom is that forms can't be nested (read Jake's excellent article for more info). If you want it in a specific position on the page, CSS may help you.
The reason for iframe and not XHR (Ajax), is that XHR returns text. With the iframe, I can more or less pick what I want out of the "iframed" document, the way I would on the "main" document.
>> The demoapp (Names-form)
Tested in Opera 9, IE7 (Vista) and Firefox 2
Thursday, January 24, 2008
Serving Gzipped content - Test for browser-support
In the newest version of the CMS I'm working on/maintaining, a couple of customers got strange errors. The culprit was that for some reason or other, their browser didn't accept gzipped content.
acceptsGzip := ( @Contains( @GetHTTPHeader( "Accept-Encoding" ) ; "gzip" ) );
{<script src="/} + @WebDbName +
@If( acceptsGzip ; "/gz/mootools.js" ; "/lib/mootools.js" ) + {"></script>}
The workaround
acceptsGzip := ( @Contains( @GetHTTPHeader( "Accept-Encoding" ) ; "gzip" ) );
{<script src="/} + @WebDbName +
@If( acceptsGzip ; "/gz/mootools.js" ; "/lib/mootools.js" ) + {"></script>}