Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Monday, September 21, 2009

Interesting talk about Server Side JS

From YUI theater.



Some valid points about advantages with programming in JS in the client and on the server.

Wednesday, April 22, 2009

XPages: Workarounds for lack of Regular Expression functionality

I wrote these two String methods as workarounds for the previously mentioned missing Regular Expression functionality.

// Finds all occurences of a substring in a string using a regular expression
// Similar to real JavaScript RegExp match with 'g' modifier
String.prototype.matchAll = function( regExp ){
// The input String
var string = this;

// Find all matches/add to matches-array
var matches = [];
while( string.match( regExp ) ){
matches.push( string.match( regExp )[0] );
string = string.replace( regExp, '' );
}
return matches;
}

// Replace all occurences of a substring using a function
// Similar to real JavaScript, where you can pass a function as the second argument
String.prototype.replaceAllFn = function( regExp, fn ){
// The input String
var string = this;

// Array used to find matches withing the string
var matchArray = null;
// JavaScript equivalent keeps track of the position of the substrings
var position = null;

while( matchArray = string.match( regExp ) ){
position = string.search( regExp );

// Replace substring(s) in the string using the supplied function
// Input parameters to the supplied function: all matches withing the
// string, the position of the match, the full string
string = string.replace( matchArray[0],
fn.apply( this, matchArray.concat( position, string ) ) );
}
return string;
}


Examples:

// Find all substrings withing braces
'{lastName}, {firstName}'.matchAll( /\{(\w+)\}/g );
// Result, array with two items: ["{lastName}", "{firstName}"]


// Map object properties to a string template
var object = { firstName: 'Tommy', lastName: 'Valand' };
var template = '{lastName}, {firstName}';
template.replaceAllFn( /\{(\w+)\}/, function( item, key ){
return object[key] || '';
});
// Result: "Valand, Tommy"

// Convert CSS to camelCase
"-moz-border-radius".replaceAllFn(/-\w/g, function( string ){
return string.replace('-','').toUpperCase();
});
// Result: MozBorderRadius

// Calculate celcius from fahrenheit
"212F".replaceAllFn(/(\d+(?:\.\d*)?)F\b/g, function(str, p1, offset, s){
return ((p1-32) * 5/9) + "C";
});
//Result: 100C


As others have mentioned, closures seems to work in XPages' pseudo-JavaScript.

Example:
function testWithClosures(){
var object = { firstName: 'Tommy', lastName: 'Valand' };
var template = '{lastName}, {firstName}';
return template.replaceAllFn( /\{(\w+)\}/, function( item, key ){
return object[key] || '';
});
}

testWithClosures();
// Result: "Valand, Tommy"


If closures weren't supported, replaceAll would crash, since the object is unavailable (undefined) in the global scope. object is only available in the scope that the "replace-function" was created.

Also, if you didn't already notice it, you can extend native objects as you can with the native objects in the web browsers. Thread carefully though.. :)

If you find any bugs in regards to the JavaScript methods being emulated, let me know.

There is (at least) one serious bug with my replaceAllFn method.
'test'.replaceAllFn( /t/, function(){ return 't'; } results in an eternal loop.
I'll try to find a better way.

Monday, October 27, 2008

Domino Developer Plugin for Aptana Studio - Version 0.6.0 Now Available

Just got a mail about a new version of the plugin.

This update features:
* Full compatibility with Aptana Studio 1.2
* Support for path/folder information in design element names
* Support for local databases
* Support for drag & drop copying to and from the file system
* Fixed last byte truncation bug affecting certain file resource lengths
* Improved performance retrieving design elements from large databases

For a complete list of changes in this release:
http://code.google.com/p/domino-aptana/issues/list?can=1&q=milestone:Release0.6

To install or upgrade to this version, point your Eclipse/Aptanaupdate manager to:
http://www.jeffgilfelt.com/eclipseplugins/

For further information and complete installation instructions:
http://www.jeffgilfelt.com/DominoAptana/

To participate in the project or to access the source code:
http://code.google.com/p/domino-aptana/

I know I'm downloading it. If you work with CSS and/or Javascript-files for Notes/Domino applications, I recommend that you try it out.

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.

Wednesday, May 14, 2008

StrToken/@Word in JavaScript


function strToken( string, separator, position ){
//If the string doesn't contain the separator, return
//empty string
if( string.indexOf( separator ) == -1 ){ return ''; }

var arr = string.split( separator );

//If the position is larger than the number of elements,
//return empty string
if( position > arr.length ){ return ''; }

//Return found item
return arr[ position - 1 ];
}



Tested in IE6/FF2

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:
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

Wednesday, March 26, 2008

Simple function to trim JS string arrays

Update, 08.05.08:
A better trimming-function:

function trimArray( array ){
var trimmedArray = [];

var item;
for( var i = 0, len=array.length ; i < len ; i++ ){
item = array[i];

if( item !== '' ){
trimmedArray.push( item );
}
}

return trimmedArray;
}



Had a case at work where I needed to make a breadcrumb-like thingy.

The breadcrumb consisted of either two or three elements, and got it's values from form-fields. Instead of checking the fields for values, I put the values in an array, trim the empty values, and join the array with a separator.

The trimming-function:

/* Trim empty strings from JS string-Arrays */
function trimStringArray( array ){
return array.join( ',' ).replace( /,{2,}/g, ',').split( ',' );
}



Testcode for the Firebug-console.

Result (in Firebug):

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.
..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 )

Friday, January 11, 2008

Taking visual control of Domino generated views

This is somewhat related to my previous post, as that is what sprung this idea forward, adding a class-attribute per even row/colgroup-nodes per column, dynamically.

In the downloadable demo application, I've made a $$ViewTemplateDefault-form with a JS-function that does the above, onload.

Every even row has class="even". The generated colgroup is structured like this, a <colgroup> containing <col id="column[number]"/> nodes, where [number] corresponds to the column number it represents.

To get a fix on the Domino-generated table, I've added a span around an embedded view (to easier control count). id="domino_view", class="@ViewTitle[1]".

I don't know what more to say than take a look at the screenshots, and download the app, look at the code/css if you think it's something you can use.

Some screenshots


Categorized view, no CSS
Categorized view, styled

Flat view, no CSS
Flat view, styled

>> The demo application

Tested in IE 6/7, FF2 and Opera 9.

If you discover bugs/find something strange in the demo-app/etc, let me know. Preferably through comments.. :)

Tuesday, December 4, 2007

Rant about the apparent lack of "serious" Notes/Domino programmers

Started of as a comment on "The reason the Domino Development Platform Isn't Taken Seriously", where Craig asks if it's time for the DominoDevs to grow up. My rant is also influenced by the comments posted on Nathan's "Sanity Check" that OO is the way to go/most N/D developers are lazy.

Start rant:
This is just a wild guess, but don't think that the majority of N/D developers are willing/able to make the effort to write "serious" code.

Then again, how many applications need the complexity that is Java/OO/Inheritance/MVC/etc?

The recent discussions on the future of N/D remind me a lot about discussions about JavaScript, which also has had the toy stigma for most of it's life.

It's not until the Ajax-term is coined by a well respected person in the community, Jesse James Garrett, that suddenly JavaScript is THE language to learn. Then Douglas Crockford steps in and show the "serious programmers" all the amazing stuff you can do in JS, and all of a sudden, all platforms must have JavaScript.

Now the "serious programmers" want to tighten JS (with EcmaScript 4), and make it more serious (or more precisely, make it fit their world..?).

JavaScript is a forgiving language, just as LS. There is a lot of awful code being written in JS, making sites/applications brittle/insecure. If you force strong typing/classical inheritance/etc. on all JavaScript-developers (as some feel that EcmaScript 4 will), how many are you going to have left? Will the tightening of the language be worth the loss? Is the proposed tightening of the N/D-platform going to be worth the loss of less advanced programmers?

I believe that what we as a community (and Notes/Domino as a platform) need, are people who love and understand what is great about the platform, and also are able to sell the concept to developers -and- IBM. Until I see the next designer, I'm firmly convinced that the decision makers of Lotus/IBM doesn't understand what is great about the platform. From looking the latest releases (6/7/8), they see it as a collaboration/mailing platform. N/D isn't great because IBM has made a great mail/calendar application with it, but maybe the mail application is so great because of the (mysterious/genious) concept that is Notes/Domino..?

Regarding lazy/untrained developers:
Great code != Great application from the users perspective, just as Horrible code != Horrible application. Great code will probably lead to a more stable/secure/maintainable/expensive application.

If you want N/D developers to write serious code, and you believe you know how to teach them, why not go together with other great minds and write a book to enlighten them? There must be publishers willing to still publish N/D books..?

With all the Agile development books coming out recently, where is "Agile application development with Notes/Domino" (horrible title, I know).

Other titles I'd like to see:
"Web 2.0 with Domino" (although I hate the term web 2.0, it sells)
"Rich Internet Applications with Domino"
"Enterprise applications with Domino 8"
"Object Orientated programming in LS for dummies"
"Taking advantage of DB2 with Domino 8"
etc. etc.

/rant

Thursday, November 29, 2007

Notes/Web JS to get text from aliased combobox/dialog list

Something I needed today. Thought i could share it with you. Easy to make, but sometimes one forgets that Notes supports JS.

>>Flash-demo
I forgot to refresh, so the alias doesn't show :)

The reason I didn't use "Refresh field on keyword change" is that it's awful on web (reloads the page).

The alias of the combobox/dialog list was the corresponding number to the text (One|1, etc).

>>Demo-application

In Notes, the code also works with hidden/computed fields. For computed fields, set value = @ThisValue.

For the web, you should probably set the text-field to editable, "HTML Attributes" -> "type=\"hidden\"".

In Notes, onChange fires when the field looses focus/value has changed. On the web, the event fires when you select another value.

JS-header - Common Javascript:

function textFromMultivalue( multival, valuefield ){
var f = document.forms[0];
/*if valuefield is the name of the value-field,
get field from form */
var valuefield = ( typeof valuefield == 'string' ) ?
f[valuefield] :
valuefield;
/*if multival is the name of the multival-field,
get field from form */
var multival = ( typeof multival == 'string' ) ?
f[multival] :
multival;

valuefield.value = multival.options[
multival.selectedIndex ].text;
}

onChange in multi-value field (also Common Javascript):
textFromMultivalue( this, 'name_of_textfield' );

Tuesday, March 20, 2007

(mis?)Using $$ReturnGeneralError as a shortcut for search

Lets the users search like this:
http://example.holidays.no/index.nsf/tokyo
Everything in regard to Tokyo

http://example.holidays.no/index.nsf/hotels/tokyo
Hotels in tokyo

http://example.holidays.no/index.nsf/restaurants/sushi
Restaurants that serve sushi


In the HTTP Head Content of $$ReturnGeneralError, add a little JavaScript to extract what is typed after the path to the database (application if you're using N8 beta ;) ).

"<script>
var db='"+@WebDbName+"';
var loc=document.location.href;
var viewToSearchIn = '($People)'; //if not specified
var newloc;

//if searchview->error, return general error

if(loc.toLowerCase().indexOf('searchview')==-1){
var query=loc.split(db)[1].replace('/','');
if(query.indexOf('/')!=-1){
viewToSearchIn = query.split('/')[0];
var tmpquery = query.split('/')[1];
newloc=loc.replace(query,viewToSearchIn+'?searchview&query='+tmpquery);
}
else{
newloc=loc.replace(query,viewToSearchIn+'?searchview&query='+query);
}

query=query.replace(/s/g,'+and+');//replace whitespace with +and+

//avoid the back-button pointing to the erroneous url
document.location.replace(newloc);
}
</script>"

Above I'm using a view called ($People), to search in. You can pass the "query" to whatever you want.

Demo application
You have to create the full-text index on the db yourself to searh on the web.

This is the same as Jake's FakeNames.nsf, but I changed the $$ReturnGeneralError form.

Tested URLs:
http://yourdomain.com/fakenames.nsf/tommy
Searches in the default view, ($People)

http://localhost/fakenames.nsf/peoplecat/abigail
Searches in the peoplecat view

http://localhost/fakenames.nsf/holidays/aus*
Searches in the holidays view

With the last view, you can also write: http://localhost/fakenames.nsf/holidays/austria
which opens the austria document (sorted view).

You can of course take this even further, with per-application mapping-documents for particular searches.

Saturday, March 17, 2007

Simple way to check if a Domino Server is online

This is a small one, but I thought it was a nice example how nice and powerful events in JavaScript are.

The images (<img> tag) on the web has an onerror-event that fires if the image in the src is either an invalid image, or the image is not found (404). Every Domino server has an icons-folder. The most used icon/image is ecblank.gif, which Notes uses in many nasty ways on the web.

To check if a notes-server is online, you simply make an image tag with src=http://serverdomain.com/icons/ecblank.gif
onerror, change some text, pop an alertbox up etc.

In my simple demo, I add a css class to a a div, and replace() innerHTML with a status.

Demo (view source to see how it is done)

If you want to automate the testing of online-status on your company's servers, you can use the Windows API's UrlDownloadToFile ( example ) to download ecblank.gif. OnError - log error, send mail etc.

Sunday, March 11, 2007

Bookmarklet to animate the clouds on Twitter.com


Opera/FF:
javascript:(function(){_c=0;d_=document; d_.styleSheets[0].insertRule("div, h1{opacity:0.7}",2);d_.body.style.backgroundRepeat="repeat-x"; setInterval(function(){ d_.body.style.backgroundPosition=(_c++)+"px top"; },40);})()

IE:
javascript:(function(){_c=0; d_=document;d_.styleSheets[0].addRule("div","filter:alpha(opacity=70)}",2); d_.body.style.backgroundRepeat="repeat-x";setInterval(function(){ d_.body.style.backgroundPosition=(_c++)+"px top";},40);})()


Test it out on http://www.twitter.com

It makes the content partly transparent, and the clouds flow towards the right.

The reason that I made this useless bookmarklet is that I liked the clouds when they were positionary, but I wanted to see how they looked moving about.

The animation is quite CPU-intensive.. Not sure how to optimize this..

Thursday, March 8, 2007

Breaking the count-limit in views on the web

Show n' Tell Thursday
I thought I'd sit this Thursday out, but too much free time I guess.

First, open the demo-db in notes.
Click Create test-documents (creates 5001 documents).
Open the view on the web.
A counter will tell how many "documents" currently fetched

The parsing of the HTML is quite CPU-intensive.
On my PC it takes IE7 about 15 seconds, and FF about 20 seconds to get all 5001 items.

There are more elegant ways of getting more documents than the server-limit. With this method, you can control the layout from the view, and you don't have to mess about with XML or JSON.

If someone can provide me with a more complex database with 1500+ (non-sensitive) documents, I can try to add browser-side click-to-sort columns.

Demo-db: NoCountLimit.zip

Screenshots:

Top


Bottom

Wednesday, March 7, 2007

Greasemonkey script: Select text to make temporary link

Not the most impressive code (I still don't understand closures in JS fully), but it works with what I've tested it on..

Select a text-link, and a temporary pop-up with a real link is created from the selection. Se picture at the end.

Tested in Opera 9.x (download/put it in the user-script folder) and FireFox 2.0.

The script

Example URLs:
www.google.com
www.google.com/analytics



Opera - User JS
About greasemonkey

Update 1: I've found some sites it doesn't work on. I will try to find out the difference between sites that work, and sites that don't. Probably JS-libs used on the sites messing with my script. :8

Update2: I've no rewritten the script so that is doesn't add any symbols to the global namespace.

Result of running the script through JSLint:
Global: document (?), setTimeout (?), window (?)

Wednesday, February 28, 2007

Cross client (Web/Notes) validation using JavaScript

Show n' Tell Thursday

Update 02.03.07

I've been working on a simple method for cross-client validation ever since I discovered how powerful the JS-methods in the Notes client was. Of course, it can't compare to the JS-engines in the web-browser, but you can still have a lot of (geek-) fun with what's available.

Since this is a Show'n Tell Thursday post, it's only reasonable to post the validation-demo database for people to play with.

If you just want to se how it works, I've prepared two flash-animations demoing how it looks in Notes, and how it looks on the web.

In the Notes client

On the web

For the web, I'm using Dexagogo's lovely validation library. I've also overloaded Notes' _doClick function so that it only runs if the form is valid (look in the database for the code).

In notes, the DOM is too simple to be able to do any real animation. I've made a simple "yellow fade". To achieve this, and to always have the error-messages available to view for the user, I've had to use a frameset. The validation script in notes is pretty crude.

The script that both Notes and Web use

And finally, the database. In Notes, the demo is the "WithValidation" frameset. On the web, open the "FramedValidation" form (forgot to rename the form to a better name before I uploaded the zip). FramedValidation is also used in Notes as the main form.

Other fun things you can do with JS in the Client:

Run LotusScript by triggering Entering/Exiting events
document.forms[0].fieldName.focus();
document.forms[0].fieldName.blur();


Use LS libraries (JS2LS anyone?)

To do this, fill value of field equal to a function-call (e.g. ..value="Call refreshForm()").

In the Entering event on the field, execute the value. Or, you could have a field for the method you're after, and just focus() on the field. You can hide the field with a layer (put it in a subform to make it re-usable).

Fill data in fields across framesets
FrameName.do...rms[0].fieldName.value="value";

Fill data into computed fields
document.forms[0].fieldName.value="value";
(same with editable fields)

Use regular expression to validate fields.

Some of the stuff that I couldn't get to work:

Cross frameset event-triggering.

Using focus() to jump from a Native OS Field (with focus) to a Notes-field. Most people probably use either one or the other type, so this is probably not a big issue.

Click on buttons/actions using click(). They don't seem to be in the Notes' DOM.

Tell me the rest. I've probably (hopefully) just scratched the surface. :)

Update (02.03.07): Per Kevin's request, I've added a form where you can make per-form configurations. I placed a field on the demo-form with a @DbLookup that gets the configuration. Using eval, I convert the config-field to an object.

The structure of the validations is that of an Object literal. Once you understand how it works, it's really quite simple.

Do a google search on "Object literal" or "JSON" for more information.

I've also added a simple menu in notes, and a simple JS-testing frameset.


v0.001 (old)

v0.002 (new)

Saturday, February 24, 2007

Validation with "Yellow-fade" in the Notes Client

I'm not done yet with JavaScript in the Notes Client.. :D






(The fade is a lot smoother in reality. Low framerate on the flash.)

The yellow-fade can be done on the form you're typing in as well, but that wouldn't look nice. The first field with error gets focus. I'm using setInterval and an array of color-codes to animate the background.

There are advantages and disadvantages using framesets for debugging.
Advantages:
- Always visible (layers are absolutely positioned). If there are many invalid entries, it's easy to forget what was invalid (messagebox)
- You can "animate" the background-color independently of the other frames (FrameName.bgColor)

Disadvantages:
- Always visible (takes up screen estate)

What I don't seem to get around, is using notes-fields for the error messages. This means that you see that they are editable fields. Native OS-fields, which can be borderless doesn't seem to be able to have transparent background(?), and I don't have write-access to computed fields with JavaScript.

I could use a hack to execute Lotus-Script. An editable field hidden by a layer.
Set the value of the field with javascript, "status-header;status message", where status-header in the example above would be error. OnExit ( field.blur() ) on the "LS-field", set value of computed fields (split by ";"). The problem with this is that you have to move the "hiding-layer" every time you add content to the form.


27.02.07 Forget the above. I just tried again. It totally works setting computed field values using javascript.


I'm testing out the possibilities for cross-client (web/notes) for the most common validations. The scripts that gives functionality to the validation would be different according to the client (on the web, using framesets is not an option). What would be common would be the syntax for which fields should be validated, and how they should be validated.

To say which fields should be validated, in the current version, I only need to type this:

var doValidationOn = {
"notEmpty": {"ktype":"Customer Type", "forename":"First Name"}
}

The syntax is:
{
"name of validation" : {
"stored name of field":"Title to show",
"etc":"etcTitle","and so":"on.."
}
}

I think there are smarter solutions. I'm also going to try to add a className-attribute on all fields that's inn an array onload. Although these className's will have no effect on the field in Notes, they can be used on the web for "Really easy field validation", and since every element in the client is an object, I can (probably) use that property to control the notes validation.

var fieldValidation = {
//name of validation : {"stored field":"field title"}
"required" : {"first_name":"First name","last_name": "Last name"},
"date" : {"date_of_birth" : "Birthdate"}
}

By the way, I'm sorry that i have no structure in my posts.. It's all down to lazyness. My plan for this post was just to post the flash, but then my head started butting in.. :[

Tuesday, February 20, 2007

Javascript in Lotus Notes Applications

To get info about a "javascript object", for instance the form, make an action button (client javascrip) with this code:

var f = eval(prompt("State the object (e.g. window, document,forms[0])","document.forms[0]"));
var str="";
for(item in f){ str+=item+" = "+f[item]+"\n"; }
alert(str);

This code puts up a prompt asking for the name of the object.

Example (using document.forms[0]):
Using window:


As far as I can tell, you have access to the form elements as you would on the web. You can also override @Command([FileSave]) with the onSubmit event (client->javascript).

If you have five fields named field1, field2, field3, field4, field5.

You can have validate that all the field has values onsubmit:
var allHaveValues = true;
var f = document.forms[0];

for(var i=1;i<6;i++){
if(f['field'+i].value==""){
allHaveValues = false;
alert("field"+i+" doesn't have a value.");
break;
}
}
return allHaveValues; //false if one off them doesn't have value No formula or lotusscript needed. Now.. Someone tell me how to add events in an unobtrusive /dynamic way in notes-applications, and I'll be a happy young lad. :)

Update: It looks like there is full support javascript objects as well.

You can for instance write:
var Form = {
getValue : function(field){
switch(field.type){
case "text":return field.value;break;
case "radio":return getRadioVal();break;
}
},
setValue:function(field, value){
alert("Not yet implemented! You get the point..");
}
}