Posts Tagged: ‘Dojo Toolkit’

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!

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.

Der neue HTTP Header ‘X-XspRefreshId’

5. Dezember 2011 Posted by Sven Hasselbach

Mit Domino 8.5.3 ist der neue HTTP Header ‘X-XspRefreshId’ eingeführt worden, mit dem sich die refreshId eines Partial Refreshs vom Server aus verändern lässt. Dadurch ist es möglich, ein Element zu refreshen, dass Ergebnis dieser Operation jedoch auf ein anderes Element im Client anzuwenden.

Hier ein kleines Beispiel anhand einer XPage, die vor dem Partial Refresh wie folgt aussieht:

Screenshot: Vor dem Partial Refresh

Der Code der XPage ist ebenfalls simpel, ausser das bei einem Partial Refresh der XPage ein Header an den Request angefügt wird. Dazu wird das Event afterRestoreView genutzt.

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

    <xp:this.afterRestoreView><![CDATA[#{javascript:
        var exCon = facesContext.getExternalContext();
        var writer = facesContext.getResponseWriter();
        var response = exCon.getResponse();
        response.setHeader("X-XspRefreshId",  getClientId('label2') ); }]]>
    </xp:this.afterRestoreView>

    <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:br></xp:br>
    <xp:label value="Label1" id="label1"></xp:label>
    <xp:br></xp:br>
    <xp:br></xp:br>
    <xp:label value="Label2" id="label2"></xp:label>
</xp:view>

Der Button löst einen Partial Refresh auf das Label label1 aus, der dazugehörige Request, der an den Server gesendet wird liefert auch den zu erwartenden HTML-Code zurück:

<span id="view:_id1:label1" class="xspTextLabel">Label1</span>

Doch nun kommt der zusätzliche Header ins Spiel. Er bewirkt, dass nicht das label1 ersetzt wird, sondern das Element label2:

Durch den in der HTTP Header in der Antwort des Servers wurde das XSP-Objekt dazu veranlasst, den HTML-Code im DOM-Baum an einer anderen Stelle zu ersetzen.

In diesem kleinen Beispiel tritt ein kleiner Seiteneffekt auf: Das Label mit der id label2 verschwindet komplett aus dem DOM-Baum. Betätigt man den Button ein zweites Mal, funktioniert der Refresh nicht mehr, und folgende Fehlermeldung erscheint im Browser:

Abbrechen eines Partial Refresh im Client

4. Dezember 2011 Posted by Sven Hasselbach

Leider bietet das XSP-Objekt keine Möglichkeit, einen Partial Refresh via CSJS vorzeitig zu beenden. Zwar basiert der Partial Refresh-Mechanismus auf dojo.xhr-Requests, die diese Funktionalität bieten, doch das XSP-Objekt stellt keine Möglichkeit zur Verfügung, auf die darunter liegenden Dojo-Objekte zuzugreifen.

Um dennoch Zugriff auf die Requests zu erhalten, müssen die Aufrufe von dojo.xhrGet und dojo.xhrPost daher direkt abgefangen und umgebogen werden. Dadurch kann auf das  zurück gelieferte dojo.Deferred-Objekt zugegriffen werden und es lassen sich dessen Methoden verwenden.

Hier ein kleines Beispielskript, dass diese Aufgabe verrichtet. Es muss in einen CSJS-Scriptblock eingebettet werden:

var xhrCall = null;

dojo.addOnLoad( function(){
   /*** hijack dojo's xhrRequest ***/
   dojo._xhrPost = dojo.xhrPost;
   dojo._xhrGet = dojo.xhrGet;

   dojo.xhrPost = function( args ){
      xhrCall = dojo._xhrPost( args );
   }

   dojo.xhrGet = function( args ){
      xhrCall = dojo._xhrGet( args );
   }
});

Will man nun im Client einen Partial Refresh abbrechen, muss nur die cancel-Methode des dojo.Deferred-Objektes aufgerufen werden, und der Partial Refresh wird beendet*:

xhrCall.cancel();

[Die Methode cancel ist unter Dojo 1.3 dokumentiert; in höheren Versionen ist sie aber aus Kompatibilitätsgründen weiterhin vorhanden.]

Das Abbrechen eines Requestes wird allerdings als Partial Refresh-Fehler betrachtet. Um die Popup-Meldung des XSP-Objekts zu unterbinden, muss dem Partial Refresh noch ein eigener Error-Handler mitgegeben werden. Dieser darf ruhig leer sein, er sorgt nur dafür, daß die Fehlermeldung unterdrückt wird:

XSP.partialRefreshGet('id', { onError: function(){} } );

*: Der eigentliche AJAX-Request wird nicht abgebrochen, sondern die weitere Verarbeitung im CSJS unterbunden.

OpenNTF XSnippets Beta gestartet

22. November 2011 Posted by Sven Hasselbach

XSnippets – The next generation code bin, ist als Beta gestartet.

Das neue OpenNTF Projekt dient als Sammlung für kleine Code-Schnippsel, die von der Community für die Community zur Verfügung gestellt werden. Hier sind die ersten Schnippsel zu finden.

Application-Properties mittels SSJS auslesen

13. November 2011 Posted by Sven Hasselbach

Um Serverseitig zu ermitteln, welche Dojo-Version verwendet wird, kann folgender Code verwendet werden:

<xp:label id="lblJSVersion">
   <xp:this.value><![CDATA[#{javascript:var reqParam =
      new com.ibm.xsp.context.RequestParameters ( facesContext );
      reqParam.getLibraryVersion()}]]>
   </xp:this.value>
</xp:label>

[Code liefert unter 8.5.3 in der Standard-Einstellung "1.6.1" zurück]

Um zu ermitteln, ob die Clientseitige Validierung aktiviert bzw. deaktiviert ist, liefert die Methode isClientSideValidation() das gewünschte Ergebnis:

<xp:label id="lblIsCSValidation">
   <xp:this.value><![CDATA[#{javascript: var reqParam =
      new com.ibm.xsp.context.RequestParameters ( facesContext );
      reqParam.isClientSideValidation()}]]>
   </xp:this.value>
</xp:label>

[Liefer true bzw. false zurück, je nach Einstellung der Datenbank]

Welche Komprimierungseinstellung verwendet wird, kann so ermittelt werden:

<xp:label id="lblCompressMode">
   <xp:this.value><![CDATA[#{javascript:var reqParam =
      new com.ibm.xsp.context.RequestParameters ( facesContext );
      reqParam.getCompressMode()}]]>
   </xp:this.value>
</xp:label>

[Liefert z.B. "gzip-nolength" zurück, je nach Einstellung der Datenbank]

Ob überhaupt Dojo Verwendung findet, bzw. die XSPDojoLite.js-Version, liefert folgender Code:

<xp:label id="lblJsLibrary">
   <xp:this.value><![CDATA[#{javascript:var reqParam =
      new com.ibm.xsp.context.RequestParameters ( facesContext );
      var jsLib = reqParam.getJsLibrary();

      switch(jsLib){
      case 1:
         return "dojo";
      break;
      case 2:
         return "lite";
      break;
      default:
         return "none";
      break;
      }}]]>
   </xp:this.value>
</xp:label>

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

30. Oktober 2011 Posted by Sven Hasselbach

Bei der Architektur von Web 2.0-Applikationen gibt es ein paar Besonderheiten zu beachten, die es im “alten” Web nicht gegeben hat, denn der konzeptionelle Ansatz, durch die AJAX-gestützten Abfragen nur einzelne Segmente einer Webseite zu laden (und diese Abfragen im Hintergrund durchzuführen), kann sich zu einem grundlegenden Problem entwickeln: Zum Einen leidet die Benutzbarkeit einer Applikation, denn das Verlinken der Inhalte ist nicht möglich, zum Anderen können Suchmaschinen die Seiten nicht oder nur noch teilweise indizieren.

Zum Erläuterung des Problems hier eine kleine Denksportaufgabe: Wie verlinke ich eine bestimmte Seite, z.B. die zweite Seite des XPages-Developer-Forums? Das Verlinken eines Beitrages stellt kein Problem dar, aber die zweite Seite zu verlinken ist nicht möglich.

Im “guten alten Web”, bei dem die Webseiten immer komplett geladen und die Optionen zum Großteil über URL-Parameter gesteuert werden, existiert als Nebeneffekt automatisch eine Möglichkeit, ein Bookmark zu setzen, wie z.B. hier: Domino 8.5 Forum, Seite 2, Kategorisierung eingeklappt.

Auch ist es für die Bots der Suchmaschinen viel einfacher, allen Verlinkungen innerhalb einer Webseite zu folgen, denn hinter dem Link verbirgt sich eine (neue) Seite, die es ebenfalls zu indizieren gilt.

Im Falle von XPages-Applikationen gibt es diese Möglichkeiten nicht Out-Of-The-Box. Man kann hier getrost vom “Fluch des Partial Refreshes” sprechen kann, denn so muß die Google-Spezifikation für durchsuchbare AJAX-Applikationen in die XPages händisch eingebaut werden. Und das für jeden Pager, jede Aktion, jeden Serverseitigen Link…

Um die Funktionalität der Bookmarks wieder herzustellen, kann der URL Hash “angezapft” werden; dieser muß jedoch via Javascript gesetzt bzw. ausgewertet werden. Eine Hilfe hierfür bietet der Dojo Toolkit mittels dojo.hash. Die Variante der URL Manipulation OHNE ein Neuladen der Webseite ist auch mit älteren Browsern möglich; mit HTML 5 ist die Möglichkeit geschaffen worden, die URL wirklich manipulieren zu können. Eine nette Implementierung findet sich auch unter https://github.com/balupton/history.js. Die HTML 5 – Variant e ist Serverseitig auswertbar, da sich die URL-Parameter ohne Reload der Seite setzen lassen (und im HTTP Request übertragen werden). Aber leider ist diese Funktionalität nicht in älteren Browser verfügbar.

Will man kompatibel bleiben, bleibt also nur der Weg über den URL-Hash. Im Falle eines Seitenaufrufs über ein Bookmark muß der Hash-Part der URL im Client ausgewertet werden, denn der Hash wird NICHT via HTTP Request übertragen (und damit auch nicht Serverseitig auswertbar). Erst nach dieser Auswertung können diese Informationen z.B. mit einen Partial Refresh übertragen werden.

Eine Beispiel-Implementation ist in Arbeit und wird bei Gelegenheit veröffentlicht.

Zeta-Dialog: Erweiterung um “Closable”-Parameter

7. September 2011 Posted by Sven Hasselbach

Jeremy Hodge hat den dijit.Dialog erweitert und die wunderbare Komponente ZetaDialog für die Domino-Welt bereitgestellt, einen XPages-Kompatiblen Dojo Dialog. Doch leider fehlt dem Dialog eine Kleinigkeit, nämlich die Möglichkeit, zu Verhindern, das der User das Dialogfenster per <ESC> oder Close-Icon einfach schließt.

Daher habe ich den Code ergänzt, so dass dies programmatisch unterbunden werden kann:

<xp:scriptBlock id="scriptBlockZetaDialog">
    <xp:this.value><![CDATA[dojo.addOnLoad( function(){
            dijit.byId('#{id:zeta}').setCloseButtonDisabled( true );
            dijit.byId('#{id:zeta}').show(); } )]]>
    </xp:this.value>
</xp:scriptBlock>

[In Fett: die Funktion setCloseButtonDisabled verhindert das Schließen durch den User]

Hier der vollständige ergänzte Sourcecode:

//Licensed under http://creativecommons.org/licenses/by/3.0/
//
//Modified by Sven Hasselbach: Now dialog no longer closable if required!
//http://blog.hasselba.ch
//
//Oringinal Code from Jeremy Hodge on the XPages Blog
//http://xpagesblog.com/xpages-blog/2010/4/10/xpages-compatible-dojo-dialog-reusable-component.html

// com.ZetaOne.Widget.Dialog
dojo.provide('com.ZetaOne.widget.Dialog');
dojo.require('dijit.Dialog');
(function(){
    dojo.declare("com.ZetaOne.widget.Dialog", dijit.Dialog, {
            disableCloseButton: false,
             _onKey: function(evt)
            {
                if(this.disableCloseButton &&
                   evt.charOrCode == dojo.keys.ESCAPE) return;
                this.inherited(arguments);
            },
            setCloseButtonDisabled: function(flag)
            {
                this.disableCloseButton = flag;
                this._updateCloseButtonState();
            },
            _updateCloseButtonState: function()
            {
                dojo.style(this.closeButtonNode,
                "display",this.disableCloseButton ? "none" : "block");
            },
            postCreate: function(){
                this.inherited(arguments);
                this._updateCloseButtonState();
                dojo.query('form', dojo.body())[0].appendChild(this.domNode);
            },
            _setup: function() {
                this.inherited(arguments);
                if (this.domNode.parentNode.nodeName.toLowerCase() == 'body')
                    dojo.query('form', dojo.body())[0].appendChild(this.domNode);                
            }                
        })
}());