Posts Tagged: ‘HTML’

XPages: Lost in Translation

18. September 2012 Posted by Sven Hasselbach

The localization feature is really nice and helps a lot, but you also can have some trouble using it. The first problem is that the language codes which are used in XPages are different from the language codes in java.util.Locale.

This SSJS code for example will not work:

var locale = new java.util.Locale( "fr_BE" );
context.setLocale( locale );
context.reloadPage();

It will not work because the java.util.Locale object returns “fr_be“, but the PageDetails are set to “fr_BE“, and that’s why the setting the language does not work.

<xp:text escape="true" id="computedFieldLocale">
   <xp:this.value>
      <![CDATA[#{javascript:
         var locale = new java.util.Locale( "fr_BE" );
         locale.getLanguage()}]]>
      </xp:this.value>
</xp:text>

[This SSJS Code returns "fr_be"]

[In PageDetails "fr_BE" is used]

But if you set the locale string manually with the setLocaleString() method of the context object, it works as designed.

The second problem I ran into is the aggressive transformation of all texts on a XPage. I copied a simple CSS Style definition from another database, but after copy/pasting it I was unable to see any changes in the browser, as soon I switched to another than the default language. The CSS style didn’t work anymore:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
   <style>
      .red { color:rgb(255,0,0 ) }
   </style>
   <p>TEXT</p>
</xp:view>

[Default Language, it worked]

[Other Language, not working anymore]

The CSS style was transformed by the localization feature and was now “translated”. In the generated HTML code, the tag looked like this:

<style>[en| .red { color:rgb(255,0,0 ) } ]</style>

Same result for directly copied JavaScript-Code, Text etc. (as shown in the screenshot above).

But I still love this feature. It makes developers life a lot easier.

XPages: Additional Facets for Viewpanels

16. August 2012 Posted by Sven Hasselbach

Today I found some additional facets / sections for a normal view panel component which can help to design a layout of an application. They are named like the wind directions and  are equivalent to the position information for the relevant content.

The following screenshot shows all facets in use. In the center you can see the content of the view panel. The pagers are not used, only place holders for a better demonstration:

As you can see there is some HTML source code in the top of the page visible. This happens if you are using the “north” facet. I don’t know why this happens.

Here is the source code of the demo XPage:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
    xmlns:xc="http://www.ibm.com/xsp/custom">

    <xp:viewPanel rows="10" id="viewPanel1">
        <xp:this.facets>
            <xc:ccDisplayer name="headerPager" color="255,0,0" xp:key="headerPager" />
            <xc:ccDisplayer name="footerPager" color="0,255,255" xp:key="footerPager" />
            <xc:ccDisplayer name="viewTitle" color="255,0,255" xp:key="viewTitle" />
            <xc:ccDisplayer name="south" color="0,255,0" xp:key="south" />
            <xc:ccDisplayer name="southWest" color="96,96,96" xp:key="southWest" />
            <xc:ccDisplayer name="west" color="128,128,128" xp:key="west" />
            <xc:ccDisplayer name="northWest" color="160,160,160" xp:key="northWest" />
            <xc:ccDisplayer name="north" color="255,255,0" xp:key="north" />
            <xc:ccDisplayer name="northEast" color="192,192,192" xp:key="northEast" />
            <xc:ccDisplayer name="east" color="224,224,224" xp:key="east" />
            <xc:ccDisplayer name="southEast" color="255,255,255" xp:key="southEast" />
        </xp:this.facets>
        <xp:this.data>
            <xp:dominoView var="view1" viewName="DemoView"></xp:dominoView>
        </xp:this.data>
        <xp:viewColumn columnName="Col1" id="viewColumn1">
            <xp:viewColumnHeader value="DocUNID" id="viewColumnHeader1"></xp:viewColumnHeader>
        </xp:viewColumn>
    </xp:viewPanel>
</xp:view>

And here is the custom control used.

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    <xp:this.style>
       <![CDATA[#{javascript:"height:100.0px;width:100.0%;background-color:rgb(" + compositeData.color + ")"}]]>
    </xp:this.style>
    <xp:label value="#{javascript:compositeData.name}" id="labelName">
    </xp:label>
</xp:view>

Quick-n-Dirty: HTML5 UIComponents without effort

17. Mai 2012 Posted by Sven Hasselbach

Obviously it was Chris Toohey who first has discovered the way of manipulation UIComponents with the tagName attribute: http://www.dominoguru.com/pages/xpage_xptext_tagName_options.html

 

The xp:text – element can easily manipulated to add HTML5 functionality to a XPages. By overriding the property tagName, the component can be accessed like every other UI component in the component tree.

Normally the designer only allows a small list of choices for the tagName property:

But this can be easily overwritten by manually editing the tagName attribute in the source and allows to change the generated HTML element to whatever you want.

Here is a small example for a HTML5 progessbar which can be accessed like every other UIComponent:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

   <xp:text escape="false" id="pBar" disableTheme="true">
      <xp:this.value><![CDATA[#{javascript:""}]]></xp:this.value>
      <xp:this.tagName>
         <![CDATA[#{javascript:"progress"}]]>
      </xp:this.tagName>
      <xp:this.attrs>
         <xp:attr name="value">
            <xp:this.value><![CDATA[#{javascript:
               if( !sessionScope.containsKey("pBar") )
                  sessionScope.put("pBar", 0 );

                var value = sessionScope.get("pBar");

                if( value > 100 ) value = 0;

                sessionScope.put("pBar", (value+10) );

                value
               }]]></xp:this.value>
         </xp:attr>
         <xp:attr value="100" name="max"></xp:attr>
      </xp:this.attrs>
   </xp:text>

   <xp:button value="Label" id="button1">
      <xp:eventHandler event="onclick" submit="true"
            refreshMode="partial" refreshId="pBar">
      </xp:eventHandler>
   </xp:button>

</xp:view>

The generated HTML Tag looks like this and can for example be refreshed with a partial refresh etc.

<progress id="view:_id1:pBar" value="40" max="100"></progress>

XSnippets: Cancel a partial refresh via SSJS

3. Mai 2012 Posted by Sven Hasselbach

With the assistance of Philippe Riand I was able to shorten the original idea of canceling a partial refresh to a single SSJS function.  By setting the HTTP header “X-XspRefreshId” to “@none” it is possible to get the same result as in the posting before, but there is no “Dojo hack” required.

function cancelPartialRefresh(){
   var response = facesContext.getExternalContext()
      .getResponse();
   response.setHeader("X-XspRefreshId", "@none");
   response.reset();
   response.commitResponse();
   facesContext.responseComplete();
}

To use this function you just have to call it.  Here is the same example like in the previous posting:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
   <xp:button value="Label" id="button1">
      <xp:eventHandler event="onclick" submit="true"
         refreshMode="partial" refreshId="label1">
      </xp:eventHandler>
   </xp:button>
   <xp:br/><xp:br/>
   <xp:label id="label1">
      <xp:this.value>
      <![CDATA[#{javascript:
      function cancelPartialRefresh(){
         var response = facesContext.getExternalContext()
            .getResponse();
         response.setHeader("X-XspRefreshId", "@none");
         response.reset();
         response.commitResponse();
         facesContext.responseComplete();
      }

      var ajax = new com.ibm.xsp.ajax.AjaxUtil();
      if( ajax.isAjaxPartialRefresh(facesContext) == true){
         cancelPartialRefresh();
         return; // stop execution of SSJS code
      }
      java.lang.System.currentTimeMillis();}]]>
      </xp:this.value>
   </xp:label>
</xp:view>

I have added the code to the XSnippet Contest. Here is the link to the XSnippet: http://openntf.org/XSnippets.nsf/snippet.xsp?id=cancel-partial-refresh

If you want to read more information about the HTTP header  you can read an earlier posting (Sorry, on german only).

Cancel a partial refresh via SSJS

1. Mai 2012 Posted by Sven Hasselbach

After reading Tim Tripcony’s blog post , I thought about a way how to cancel a partial refresh via server side javascript. To bring this to life, there are just three things to do:

  1. Abort the processing of the request on the server
  2. Give feedback to the client that request is canceled
  3. Stop Dojo to process the XHR request

To stop the processing of a request on the server and to send an empty response to the client, this SSJS code can be used:

var response = facesContext.getExternalContext().getResponse();
response.reset();
response.commitResponse();

The client will receive an empty HTTP response body:

A HTTP Header has to be added to the response to inform Dojo that the request was canceled. In this example it is “X-Partial-Refresh-Cancel“:

response.setHeader("X-Partial-Refresh-Cancel", "1");

The header is now added to the HTTP response and sent back to the client:

The XHR response must be hijacked before it is processed by Dojo. To do this, a new XHR function has to be injected between the existing one. Here is a basic code snippet:

var xhrLoad = null; // placeholder for the original function

if( !dojo._xhr )
   dojo._xhr = dojo.xhr;

dojo.xhr = function(){
   var args = arguments[1];
   xhrLoad = args["load"]; // "save" the original load function
                           // and overwrite with a new one
   args["load"] = function( a, ioArgs ){
      // execute custom code
      // call the original load function:
      xhrLoad( a, ioArgs );
   }

   // do XHR request
   dojo._xhr( arguments[0], arguments[1], arguments[2] );
}

The load function of a Dojo XHR request has a parameter ioArgs. This parameter gives a handle to an object that allows to access the HTTP response headers, so the response can be identified as canceled:

var canceled = ioArgs.xhr &&
   ioArgs.xhr.getResponseHeader("X-Partial-Refresh-Cancel");

if( canceled ){
   XSP.allowSubmit();
   return;
}

If the HTTP header is set, the processing of the request can be stopped. After stopping the request, the XSP object is not allowed to fire the next event. To allow this again, the function XSP.allowSubmit() must be called.

Here is a demonstration XPage with a button and a label. The partial refresh will never be processed, instead a “Canceled” message will occur.

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
   <xp:button value="Label" id="button1">
      <xp:eventHandler event="onclick" submit="true"
         refreshMode="partial" refreshId="label1">
      </xp:eventHandler>
   </xp:button>
   <xp:br/><xp:br/>
   <xp:label id="label1">
      <xp:this.value>
      <![CDATA[#{javascript:
      var response = facesContext.getExternalContext().getResponse();
      var ajax = new com.ibm.xsp.ajax.AjaxUtil();
      if( ajax.isAjaxPartialRefresh(facesContext) == true){
         response.setHeader("X-Partial-Refresh-Cancel", "1");
         response.reset();
         response.commitResponse();
         return;
      }
      java.lang.System.currentTimeMillis();}]]>
      </xp:this.value>
   </xp:label>
   <xp:br/>
   <xp:br/>
   <xp:scriptBlock id="scriptBlockXHRHandler">
   <xp:this.value><![CDATA[
      var xhrLoad = null;
      dojo.addOnLoad( function(){
         if( !dojo._xhr )
            dojo._xhr = dojo.xhr;

        dojo.xhr = function(){
           try{
              var args = arguments[1];
              xhrLoad = args["load"];
              args["load"] = function( a, ioArgs ){
                 var canceled = ioArgs.xhr &&
                    ioArgs.xhr.getResponseHeader("X-Partial-Refresh-Cancel");
                 if( canceled ){
                    alert("Canceled!");
                    XSP.allowSubmit();
                    return;
                 }
                 xhrLoad( a, ioArgs );
               }
            }catch(e){}
            dojo._xhr( arguments[0], arguments[1], arguments[2] );
         }
      });]]>
      </xp:this.value>
   </xp:scriptBlock>
</xp:view>

XSnippets: XPages Localization Setter

22. April 2012 Posted by Sven Hasselbach

I have submitted some XSnippets for the XSnippets-Contest. This is the first one, the XPages Localization Setter: The Snippet allows to change the language settings of a XPage “On-The-Fly”, including the browser language used, the dojo settings, the ressource files etc.

package ch.hasselba.xpages.jsf.core;

import javax.faces.context.FacesContext;
import javax.faces.application.Application;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.component.UIViewRoot;
import java.util.Locale;
import java.util.Map;

public class LocalizationSetter implements PhaseListener {

    private static final long serialVersionUID = -1L;
    private static final String scopeVarName = "Language";
    private static final String scopeName = "sessionScope";

    public void afterPhase(PhaseEvent event) {}

    public void beforePhase(PhaseEvent event) {
        FacesContext facesContext = event.getFacesContext();
        UIViewRoot view = facesContext.getViewRoot();
        view.setLocale( getLanguage(facesContext) ) ;
    }

    public PhaseId getPhaseId() {
        return PhaseId.RENDER_RESPONSE;
    }

    private Locale getLanguage( FacesContext facesContext ){       
        try{
            Application app = facesContext.getApplication();
            Object obj = app.getVariableResolver()
                  .resolveVariable(facesContext, scopeName );
            Object lang = ((Map) obj).get( scopeVarName );
            if( lang != null ){
                return new Locale((String) lang);
            }
        }catch(Exception e){}

        return Locale.getDefault();
    }
}

This phase listener updates the language settings of the UIViewRoot-Element during the rendering of the response. The language the XPage will be set to is stored in a session scope variable named “Language”. If you want to change this you just have to change the variable scopeVarName to fit your requirements.

To activate the phase listener in your XPages-Application you have to alter the faces-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
    <lifecycle>
        <phase-listener>
           ch.hasselba.xpages.jsf.core.LocalizationSetter
        </phase-listener>
    </lifecycle>
</faces-config>

Here is a simple example to demonstrate the XSnippet:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:comboBox id="comboBox1" value="#{sessionScope.Language}">
   <xp:selectItem itemLabel="Chinese" itemValue="zh" />
   <xp:selectItem itemLabel="German" itemValue="de" />
   <xp:selectItem itemLabel="Turkish" itemValue="tr" />
   <xp:eventHandler event="onchange" submit="true"
      refreshMode="complete" />
</xp:comboBox>
</xp:view>

If you are choosing “turkish” from the combobox, the html source looks like this after the refresh:

If you are add a simple date picker to your XPage and change the language to chinese, the dojo dialog will be in chinese from now on:

To add more languages you have to use the two letter ISO 639 code. To get a list of all available locales you can use this small repeat control:

<xp:repeat id="repeat1" rows="999" var="locale">
   <xp:this.value>
      <![CDATA[#{javascript:
         java.text.SimpleDateFormat.getAvailableLocales();
      }]]>
   </xp:this.value>
   <xp:label id="label1">
      <xp:this.value>
         <![CDATA[#{javascript:
            locale.getDisplayName() + " -> " + locale.toString()
         }]]>
      </xp:this.value>
   </xp:label>
   <xp:br/>
</xp:repeat>

Note:

After changing the language a full refresh is required!

Stumbling Stones: Difference between xp:panel and xp:div

2. April 2012 Posted by airwolf89

Today another stumbling stone.

With this post I want to announce that I will write this Blog in english from now on to reach more readers throughout the world. My old posts will be translated step by step. I hope you understand this step and continue reading my Blog.

But back to topic. Today I was customizing a module in one of my applications. The structure was implemented via xp:panel elements. I wanted to save some performance and wanted to change it to xp:div.

By the way, what is the difference between xp:panel and xp:div, you might ask. Well, it is quite easy. Both controls are container controls which are rendered as a <div> element in HTML. The difference is that you can define a datasource in xp:panel elements. Therefore, xp:panel and xp:div references different Java-classes in the backend. The class for xp:panel is more complex, that means you a bit more serverload. Here is the Java code generated:

 

xp:panel:
private UIComponent createPanel2(FacesContext context,
      UIComponent parent, PageExpressionEvaluator evaluator) {
   UIPanelEx result = new UIPanelEx();
   return result;
}

xp:div
private UIComponent createDiv(FacesContext context,
      UIComponent parent, PageExpressionEvaluator evaluator) {
   XspDiv result = new XspDiv();
   return result;
}

 

It seems not worth to mention, but imagine you have an application with, let’s say 200 div containers throughout the application. With each the server has to load the more complex class and prepare the functionality to create a datasource. If you use xp:div instead, the serverload may decrease a bit. I do not have some statistics to prove how it affects the applications performance in detail, but it is alsways a good idea to reach for maximum performance of an application.

So, what was the problem? I changed the tags to xp:div, and the design of my module was affected. I wondered, because I was thinking both elements are rendered as a <div> element in HTML. But a short glance into the Firebug told me something. For two panels, I didn’t define an ID attribute. So, the second difference between xp:div and xp:panel is that xp:panels without an ID attribute are NOT rendered in an XPage. This could affect either some CSS hierarchies and also, if you need every pixel in a container, affects the way it is displayed. In my case it had the result that an image, which I used as a button was not displayed next to an inputBox, it was displayed below that.

Here an example with the output:

 

Without IDs:

XSP:
<xp:panel>
   <xp:panel>
      test 1
   </xp:panel>
</xp:panel>

<xp:br/>

<xp:div>
   <xp:div>
      test 2
   </xp:div>
</xp:div>

HTML:
test 1
<br>
<div>
   <div>
      test 2
   </div>
</div>

With IDs:

XSP:
<xp:panel id="panel1">
   <xp:panel id="panel2">
      test 1
   </xp:panel>
</xp:panel>

<xp:br/>

<xp:div id="div1">
   <xp:div id="div2">
      test 2
   </xp:div>
</xp:div>

HTML:
<div id="view:_id1:panel1">
   <div id="view:_id1:panel2">
      test 1
   </div>
</div>
<br>
<div id="view:_id1:div1">
   <div id="view:_id1:div2">
      test 2
   </div>
</div>

 

This is not a big deal, if you know that and always set an ID attribut, as it should be, you won’t encounter that problem. But like it is always, you have to know it or you get confused by its consequences.


Filed under: Stumbling Stones Tagged: Attribute, CSS, Datasource, Hierarchy, HTML, Java, Notes, Stumbling Stone, xp:div, xp:panel, XPages

Quick-n-Dirty: Locale setzen

5. Januar 2012 Posted by Sven Hasselbach

Um die Locale-Einstellung einer XPage programmatisch zu beeinflussen, kann die Methode setLocaleString bzw. setLocale des context-Objektes verwendet werden.  Damit die Änderungen übernommen wird, muss die Einstellung im BeforePageLoad gesetzt werden.

So ändert ein…

context.setLocaleString("zh-tw")

… bzw. ein …

context.setLocale(java.util.Locale.TAIWAN)

…die Spracheinstellungen der generierten XPage. Sowohl das lang-Attribute der HTML-Seite als die Dojo-Konfiguration wird dabei gesetzt:

<!DOCTYPE html>
<html lang="zh-tw">
<script type="text/javascript"
src="/xsp/.ibmxspres/dojoroot-1.6.1/dojo/dojo.js"
djConfig="locale: 'zh-tw', parseOnLoad: true"></script>

Durch diese Änderung wird z.B. der Datepicker-Dialog des DojoToolkit auf Taiwanisch gerendert.

Eine Liste der möglichen Einstellungen findet sich in der Beschreibung des java.util.Locale-Objektes.

Quick-n-Dirty: Hijacking TypeAhead in CSJS

9. Dezember 2011 Posted by Sven Hasselbach

Matthias Nicklisch hat eine interessante Frage im XPages Forum gestellt, nachdem er festgestellt hat, dass im Designer zwar ein OnStart- / OnComplete-Event für die TypeAhead-Funktion angeboten wird, der Code aber als Deprecated angezeigt wird – und auf der XPage auch nicht funktioniert: Wie kann ein OnStart- / OnComplete-Event trotzdem verwendet werden?

Meine Idee dazu ist, den darunter liegenden dojo.xhr-Request zu hijacken, und auf diese Weise die Events zu erhalten. Dadurch lässt sich der Code bequem auf die jeweilige XPage einbetten, ohne das eine Manipulation der original Javascript-Dateien erfolgen muss.

Der folgender Code muß in einem CSJS-Scriptblock eingebettet werden. Dann erhält man für die TypeAhead-Funktion die Events, um zum Beispiel ein kleines “Loading”-Icon einzublenden, wenn die Daten vom Domino Server geladen werden.

var typeAheadLoad;

dojo.addOnLoad( function(){
   /*** hijacking xhr request ***/
   if( !dojo._xhr )
      dojo._xhr = dojo.xhr;

   dojo.xhr = function(){
      try{
         var args = arguments[1];
         if( args['content'] ){
            var content = args['content'];
               if( content['$$ajaxmode'] ){
                  if( content['$$ajaxmode'] == "typeahead" ){
                
                     /*** hook in load function ***/
                     typeAheadLoad = args["load"];

                     /*** overwrite error function ***/
                     args["error"] = function(){
                        alert('Error raised!')
                     };
                    
                     /*** hijack load function ***/
                     args["load"] = function(arguments){
                 
                        /*** On Start ***/
                        alert("On Start!");
                    
                        /*** call original function ***/
                        typeAheadLoad(arguments);
                    
                        /*** On Complete ***/
                        alert("On Complete!")
                     };
                 }
             }
         }
      }catch(e){}
      dojo._xhr( arguments[0], arguments[1], arguments[2] );
   }
});

Performance-Tuning (6): Parallele Partial Refreshs

7. Dezember 2011 Posted by Sven Hasselbach

Multiple Partial Refreshs sind eine schöne Sache, um mehrere Elemente einer XPage zu aktualisieren. Doch da die AJAX-Requests generell asynchron verarbeitet werden, stellt sich die Frage, in wieweit es erforderlich ist, sie sequentiell wie in dem verlinkten Beispiel abzuarbeiten: Denn je länger die Kette der Partial Refreshs ist, desto mehr Performance gewinnt man, wenn man stattdessen mit parallenen Aufrufen arbeitet.

Das verlinkte Beispiel sieht in der parallelen Variante wie folgt aus:

XSP.partialRefreshGet(id1);
XSP.allowSubmit();
XSP.partialRefreshGet(id2);
XSP.allowSubmit();
XSP.partialRefreshGet(id3);

Das Ergebnis unterscheidet sich nicht von von der sequentiellen Variante, ausser der Tatsache, das die Performance im Client deutlich höher ist. Zwischen den einzelnen Partial Refreshs muss nur die Funktion XSP.allowSubmit() aufgerufen werden, um die interne “Refresh-Sperre” zurück zu setzen (Eine kurze Erläuterung hierzu findet sich in Matthias Blog).

Die Events der Parial Refreshs (OnComplete, OnError, OnStart) können natürlich wie sonst auch verwendet werden.

Wichtig ist nur, dass man eine “Feinabstimmung” vornimmt, denn es läßt sich aufgrund der Asynchronität nicht voraussagen, in welcher Reihenfolge die Partial Refreshs verarbeitet werden: Sind z.B. die Elemente im DOM-Baum voneinander abhängig und ein Element wird durch ein Partial Refresh ausgeblendet, kann das natürlich zu ungewollten Fehlern führen – und ein sequentielles Aufrufen erforderlich machen. Doch wo es möglich ist, sollte aus Performancegründen der Einsatz von parallel ausgeführten Partial Refreshs erfolgen.

Quick-n-Dirty: Das xp:hidden-Element

6. Dezember 2011 Posted by Sven Hasselbach

Durch die Verwendung des <xp:hidden>-Elements lässt sich ein verstecktes Feld auf der XPage anlegen.

Hier ein Beispiel mit einem statischen Wert:

<xp:inputHidden id="inputHidden1" value="abc" />

Die XPages-Engine rendert daraus diesen HTML-Code:

<input type="hidden" id="view:_id1:inputHidden1"
   name="view:_id1:inputHidden1" value="abc">

Soweit so gut, doch wenn man den Wert dynamisch zuweisen will, rendert die XPages-Engine nicht mehr ein referenzierbares Feld,…

<xp:inputHidden id="inputHidden1">
   <xp:this.value>
      <![CDATA[#{javascript:"abc"}]]>
   </xp:this.value>
</xp:inputHidden>

… sondern einen <span>-Tag, der natürlich auch den Wert nicht enthält:

<span id:"view:_id1:inputHidden1"></span>

Will man trotzdem den Wert des Feldes berechnen, gibt es zwei Möglichkeiten:

1. Die Berechnung wird auf Compute on page load geändert:

<xp:inputHidden id="inputHidden1">
   <xp:this.value>
      <![CDATA[${javascript:"abc"}]]>
   </xp:this.value>
</xp:inputHidden>

2. Dem Feld wird eine Scope-Variable oder einem Dokumentenfeld via EL zugewiesen

<xp:inputHidden id="inputHidden1" value="#{viewScope.hiddenField}">
<xp:inputHidden id="inputHidden1" value="#{document1.hiddenField}">

Dann wird wie in der statischen Variante ein verstecktes Feld generiert, was sich sowohl mit CSJS als auch mit SSJS verarbeiten lässt.

Performance-Tuning (4): Fein-Tuning von xsp.resources.aggregate

11. November 2011 Posted by Sven Hasselbach

Mit Domino 8.5.3 wurde eine neue Option eingeführt, mit der automatisch verschiedene Ressourcen-Dateien vom Server vor der Auslieferung an den Browser zusammengefasst werden. Dadurch läßt sich die Performance einer Web-Applikation deutlich erhöhen, denn zum Einen werden dadurch weniger Anfragen vom Browser an den Server gesendet,  zum Anderen wird der Browser nicht unnötig “blockiert”, da sich die Anzahl der zu ladenden Ressourcen deutlich reduziert (siehe dazu RFC 2616)

In folgendem Artikel ist die neue Option xsp.resources.aggregate detailliert beschrieben, doch es gibt noch ein paar undokumentierte Optionen, mit denen sich das Verhalten der XPages-Engine genauer steuern läßt.

Dafür muß zu aller erst die Funktion aktiviert sein, das xsp.properties-File also folgende Zeile beinhalten:

xsp.resources.aggregate=true

Dann kann mit den folgenden Optionen das Verhalten für die einzelnen zu aggregierenden Ressourcen individuell festgelegt werden (Standardmäßig werden alle Ressourcen zusammen gefasst).

  • xsp.resources.aggregate.dojo

Wenn false, werden die Javascript-Libraries des Dojo Toolkits ausgeschlossen.

  • xsp.resources.aggregate.css

Schließt die Standard-CSS-Dateien aus, wenn false.

  • xsp.resources.aggregate.appcss

Schließt die CSS-Dateien der Applikation aus, wenn false.

  • xsp.resources.aggregate.appjs

Wenn false, werden die JavaScript-Libraries der Applikation ausgeschlossen.

Performance-Tuning (3): XSPClientLite.js

10. November 2011 Posted by Sven Hasselbach

Im xsp.properties-File gibt es einen undokumentierten Parameter, mit der sich eine abgespeckte Version der JavaScript-Routinen im Client einbinden läßt: die XSPClientLite.js. Die Library wird bei einer Standard-Installation von der IBM mitgeliefert.

Hierbei handelt es sich um eine deutlich kleinere Version der XSP Routinen, allerdings auch mit einem kleineren Funktionsumfang: Es fehlen z.B. die Routinen für Partial Refreshs, auf die aber je nach Anwendungsfall auch verzichtet werden kann. Hingegen sind z.B. die Clientseitige Validierung enthalten, oder aber die Methoden für das Auf-/Zuklappen von Sections, uvm.

Durch die kompakte Größe von nur 11 KB (rund 2/3 kleiner als die “normale” XSPClient-Library) läßt sich aber die Ladezeit verringern bzw. der Seitenaufbau der XPage beschleunigen; ob die Library die nötigen Funktionen bietet, die man auf der XPage verwenden möchte, muß aber im Einzelfall getestet werden.

Um die Library zu verwenden, muß im xsp.properties-File folgender Eintrag hinzugefügt werden:

xsp.client.script.libraries=lite

Dadurch wird die XSPClientLite.js anstelle der XSPClientDojo.js in der XPage eingebunden und vom Client verwendet.

Quick-n-Dirty: Dojo-Version auf Datenbankebene setzen

9. November 2011 Posted by Sven Hasselbach

Will man unterschiedliche Dojo-Versionen einsetzen, ist dies nicht nur auf Serverebene möglich. Auch für jede einzelne Datenbank läßt sich die gewünschte Dojo-Version über das xsp.properties-File vorgeben.

Zwar greift die Manipulation der Dojo-Version im xsp.properties-File nur auf dem Domino-Server (die installierte Version vorausgesetzt)…

xsp.client.script.dojo.version=1.5.0

…fügt man allerdings folgende Zeile in das xsp.properties-File in der Datenbank hinzu, wird die entsprechende Dojo-Version geladen:

xsp.client.script.dojo.path=/domjs/dojo-1.5.0

[Der Pfad /domjs entspricht dem Verzeichnis \domino\js im Notes Data-Verzeichnis]

Um die korrekte Einbindung zu überrpüfen, kann die aktuelle Dojo-Version im Client mit der Funktion dojo.version ausgegeben werden.

<xp:scriptBlock id="scriptBlockDJVersion"
    value="XSP.addOnLoad( function(){ alert( dojo.version ); } );">
</xp:scriptBlock>

P.S. Leider setzt die XPages-Engine immer einen Slash vor den Pfad der eingebundenen Library, so dass die Angabe einer URL leider nicht funktioniert.

Der Fluch des Partial Refreshs (2)

3. November 2011 Posted by Sven Hasselbach

Anscheinend liest jemand bei Google meinen Blog und reagierte auf meinen Artikel:

Heise Newsticker: Googlebot erfasst künftig mehr dynamische Seiteninhalte

Jetzt müssen nur noch die Browser-Hersteller einlenken…