Prototypal inheritance of SSJS across the whole server in XPages

A friend asked me the other day how would I determine where a string lay within a JavaScript Array. I of course answered – “it depends! If you are using newer IE or a non-crappy implementation of the JavaScript engine then use Array.indexOf – it has been around for years…..”

var arr = ["simon", "marky", "david"]
return arr.indexOf("marky") // 1.0

Well – turns out the friend was asking about SSJS in XPages and it turns out that apparently XPages has one of those crappy JavaScript engines of which I spoke and Array.indexOf is not supported (facepalm). (*really??*)

<xp:text escape="true" id="computedField1">
	<xp:this.value><![CDATA[#{javascript:
		var arr = ["simon", "marky", "david"]
		return arr.indexOf("marky")
	}]]></xp:this.value>
</xp:text>

arr1

Polyfill

OK so there is a simple polyfill for the indexOf, which has also been around for years as this article written in 2007 demonstrates…..

if(!Array.indexOf){
    Array.prototype.indexOf = function(obj){
        for(var i=0; i<this.length; i++){
            if(this[i]==obj){
                return i;
            }
        }
        return -1;
    }
}

And if we add this to our XPages sample code we get the answer we are expecting….

<xp:text escape="true" id="computedField1">
	<xp:this.value><![CDATA[#{javascript:
		if(!Array.indexOf){
		    Array.prototype.indexOf = function(obj){
		        for(var i=0; i<this.length; i++){
		            if(this[i]==obj){
		                return i;
		            }
		        }
		        return -1;
		    }
		}

		var arr = ["simon", "marky", "david"]
		return arr.indexOf("marky")
	}]]></xp:this.value>
</xp:text>

arr2

Yay !

Prototyping in JavaScript

For a better explanation that I can give, check out this StackOverflow answer on what is prototyping – suffice to say that every JavaScript object has a prototype property and this is the basis for prototypal (as opposed to class based) inheritance in the JavaScript language.

What we did in the polyfill above is: we simply said if Array.indexOf method does not exist, then we created one.

So what does this have to do with XPages?

In JavaScript when you prototype a function, the scope is on the page you are looking at. As soon as you leave the page the prototype is gone. In XPages it seems to be a little broader than that…..

I (unintentionally) discovered that once you prototype the Array.indexOf, not only does it become available on the same page, it is permanently on the same page. You run the prototype code once….then take it away, and it still works. The scope would appear to be at the application level…..

Well so then I asked some people who are way smarter than I and Nathan Freeman pointed me to his article about XPages Performance Pro Tips and told me he expected that the prototype would actually be at the server level and he was right….

I included the URL of the test database in the picture above to demonstrate that when I move the simple code to another database – it still works (after the prototype code has been run once)

rr3

And just to be sure – in another browser !!

arr4

Once the Array.prototype.indexOf was created, it became available in all applications on the server, instantly.

Killing the prototype

  • Restarting HTTP *DOES NOT* stop this.
  • Killing all browsers and starting again does not stop this

As far as I can tell you have modified the way the SSJS works on the server until you kill it. So far I have run a test over 24 hours later and it is still working……

This is COOL right?

Well for one it means that you can seriously enhance all your JavaScript on the server in ways which make custom libraries look like a waste of time. We could truly add all the corporate libraries to SSJS once when the server loads and they would always be available to all developers at all times.

arr5

And the even more awesome (depending on perspective…..)

arr7

Well yeah but…….

You can also serious screw up perfectly good code across the server

arr6

Conclusion

Prototypal inheritance is at the root of JavaScript programming language and is very powerful. What we can see here though is that we are able to affect code across the entire server with a few lines of code. This is *very* cool and *very scary* at the same time.

So with this knowledge comes great responsibility – use it at your own risk and make sure you have very good server side code review if you are going to go down this path.

typeof() – lifesaving debugger tool

OK so maybe life saving is a little stretch but in this article I will illustrate an occurrence of where using type of() helped solve a real world problem.

The Problem

I wanted to display a data source within a repeat control – relatively simple situation I guess but my brain was asleep that particular morning. I wanted to display the repeat control value within a computed text control……seemed simple

	<xp:this.data>
		<xp:dominoView var="viewSortOrder" viewName="vwSortOrder"></xp:dominoView>
	</xp:this.data>
<xp:repeat var="repeatSortOrder" id="repeat1" value="#{viewSortOrder}" disableOutputTag="true">
	<xp:text tagName="li" escape="false" disableTheme="true">
		<xp:this.value><![CDATA[#{javascript:var temp=""
		temp=temp+repeatSortOrder.title //here is the repeat
		.......
	</xp:text>
</xp:repeat>

Unfortunately this created an error 500 – one of the most useless errors known to XPages but I knew something was wrong…but what?

The answer

Then to my rescue comes “Super TroyReimer” who is of course one of the smartest people I know and he says “oo I dunno let’s find out”

“Why don’t we start by finding the typeof for the repeatSortOrder”?

“errrrrr ok *shaking head and humoring MrSmartGuy*”

so I ran a quick print to the screen and look what came back?

println(typeof(repeatSortOrder))

ty1

Oh well DUH Marky……

The repeat control in this context is running a notesViewNavigator in the Java code (I knew that) and therefore in the computed context it is returning a notesview entry every time the repeat cycles….

So in that case the solution is not repeatSortOrder.title is it repeatSortOrder.getColumnValue(‘title’)

	<xp:this.data>
		<xp:dominoView var="viewSortOrder" viewName="vwSortOrder"></xp:dominoView>
	</xp:this.data>
<xp:repeat var="repeatSortOrder" id="repeat1" value="#{viewSortOrder}" disableOutputTag="true">
	<xp:text tagName="li" escape="false" disableTheme="true">
		<xp:this.value><![CDATA[#{javascript:var temp=""
		temp=temp+repeatSortOrder.getColumnValue('title') //here is the repeat
		.......
	</xp:text>
</xp:repeat>

and that works just fine

Conclusion

Troy Reimer is a very smart person

We all have brain farts and I hope you are as lucky to work with some really smart people like I am

typeof() is a very smart way of figuring out why your object is not what you think it is in SSJS