XPages & Angular.js: AngScope for Firebug

AngScope is a

„Simple Firebug extension that allows you to inspect the AngularJS scope that a DOM element binds to.“

Just do a right click on the DOM element you want to inspect and select „Inspect Angular Scope„:

This gives you a direct access to all elements of the scopes of your Angular.js application:

You can find the extension here.

Veröffentlicht unter Angular.js | Verschlagwortet mit , , , | Ein Kommentar

XPages & Angular.js: Accessing Rich Text (1)

If you want to access Rich Text with Angular.js, an easy way to get the content is to use a XPage as handler and grab the content of a XspInputRichText component. The component does all required steps automatically (f.e. it detaches all embedded images to disc and cleans up the temporary files later) and returns the complete HTML of the Rich Text item.

For the conversion I have created a small java helper class:

package ch.hasselba.xpages.util;

import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;

import com.ibm.xsp.component.xp.XspInputRichText;
import com.ibm.xsp.http.IMimeMultipart;

/**
 * Utility class for accessing RichText items
 * 
 * @author Sven Hasselbach
 * @version 1.3
 */
public class RTItemUtil {

    /**
     * 
     * @param dsName
     *            the name of the datasource to use
     * @param rtFieldName
     *            the name of the richtext item
     * @return String with the HTML
     */
    public static String getHTML(final String dsName, final String rtFieldName) {

        // get current FacesContext
        FacesContext fc = FacesContext.getCurrentInstance();

        // create a value binding for the datasource
        String expr = "#{" + dsName + "." + rtFieldName + "}";
        ValueBinding vb = fc.getApplication().createValueBinding(expr);

        // create a rich text components
        XspInputRichText uiCmp = new XspInputRichText();
        uiCmp.setValueBinding("value", vb);
        Object value = uiCmp.getValue();

        // get the value of the component as HTML
        String strHtml = null;
        if (value != null) {
            if (value instanceof IMimeMultipart) {
                IMimeMultipart mime = (IMimeMultipart) value;
                strHtml = mime.getHTML();
            } else {
                strHtml = value.toString();
            }
        }

        return strHtml;
    }

What does the method getHTML do? First, the datasource is accessed by creating a new value binding. Then a new XspInputRichText component is created on the fly which does the magic: All attachments are detachted into the temporary xsppers folder, and linked into the generated HTML code of the Rich Text item.

This is the XPage with the name „getrtdata“ which is our handle:

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

    <xp:this.data>
        <xp:dominoDocument var="documentRTItem" />
    </xp:this.data>
    
    <xp:this.afterRenderResponse>
        <![CDATA[#{javascript:
            importPackage( ch.hasselba.xpages.util );
        
            var res = facesContext.getExternalContext().getResponse();
            res.setContentType("text/html");
            res.setCharacterEncoding( "UTF-8" );
            var writer = res.getWriter();
            
            var rtUtil = new ch.hasselba.xpages.util.RTItemUtil();
            var strHtml = rtUtil.getHTML( "documentRTItem", "Body" );
            
            writer.write( strHtml );
            writer.flush();
            facesContext.responseComplete();
       }]]>
       </xp:this.afterRenderResponse>
       
</xp:view>

The datasource on the this XPage is accessed by URL parameters from our Angular.js application. The method getHTML from the utility class is called with the name of the datasource and the name of the rich text item we want to access.

Now let’s have a look at our Angular.js application. To make it a litlle bit more complicated, the data from the Rich Text item will be loaded into a CKEditor:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <script type='text/javascript' src="jquery-1.8.3.js"></script>
        <script type='text/javascript' src="http://ckeditor.com/apps/ckeditor/4.4.1/ckeditor.js"></script>  
    </head>
    
    <body data-ng-app="myApp" data-ng-controller="CKEditiorCtrl">
    
        <textarea data-ck-editor data-ng-model="ckEditor.value"></textarea>
        <br>
       
        <button ng-click="loadData( '49573FE44017DA9FC1257CEC0035CBCC' )">load data</button>
    
        <script type='text/javascript' src="angular.js"></script>
        <script type='text/javascript' src="app.js"></script>
    </body>
    
</html>

The resources of the previous article are used in this example. The lastest version of CKEditor is used, and the whole application logic is contained in the file app.js.

When opening the application in the browser, a fresh and empty CKEditor instance will be instantiated:

When clicking the button „load data„, the XPage is loaded in the background. In the Firebug console the response of the request contains the HTML markup, including the pathes to the detached attachments:

Then the CKEditor is updated with the HTML code, and displays the content of the Rich Text item:

How does the app.js looks like?

var myApp = angular.module('myApp',[]);

/**
 * the data service to load the RTItem data
 */
myApp.service('dataService', function($http) {
    delete $http.defaults.headers.common['X-Requested-With'];
    this.getData = function( id ) {
        return $http({
            method: 'GET',
            url: 'getrtdata.xsp',
            params: {
                documentId: id,
                action: 'openDocument'}
            });
    }
});

/**
 * the directive
 */
myApp.directive('ckEditor', [function () {
    return {
        require: '?ngModel',
        link: function ($scope, elm, attr, ngModel) {
            var ck = CKEDITOR.replace(elm[0]);
            ngModel.$render = function () {
                ck.setData(ngModel.$modelValue);
            };
        }
    };
}])

/**
 * the controller
 */
myApp.controller('CKEditiorCtrl', function($scope, dataService) {
    $scope.dataservice = dataService;
    $scope.ckEditor = { value: null };
    $scope.loadData = function( unid ){
        $scope.dataservice.getData( unid ).then(
            function(dataResponse) {
                   $scope.ckEditor.value = dataResponse.data;
            });
    }
    
});

The service dataService is the interface to the XPages backend: The method getData makes the HTTP request with the $http service of Angular.js. The two parameters are the document UNID and the action to perform, and are used to control the datasource of the XPage.

This service is bound to the controller, and is called by the loadData method as soon as the button is clicked. It sets the value of the ckEditor binding with the resulting data from the request. (Btw. if you have a look at the HTML of the button you will see that the used document UNID is hardcoded in this example).

But what is the directive for?

 <textarea data-ck-editor data-ng-model="ckEditor.value"></textarea>

The directive is a „link“ between Angular.js and the code of the CKEditor: The data-ck-editor attribute of the textarea is the key to our directive and is searched by Angular.js when the application is initialized. When a matching directive is found, the method link is called, with the parent DOM element as parameter. This DOM element is now replaced by a CKEditor instance. The data-ng-model attribute binds the data of the CKEditor to the defined value of our controller, the $scope.ckEditor.value. This allows to update the content of the CKEditor instance.

That’s it!

Veröffentlicht unter Allgemein, Angular.js | Verschlagwortet mit , , , , , , , | 3 Kommentare

Krautreporter: Jetzt auch mit PayPal bezahlbar

Die Krautreporter können jetzt auch per PayPal unterstüzt werden. Siehe dazu:

http://blog.krautreporter.de/post/ab-sofort-krautreporter-per-paypal-unterstuetzen/
Ich unterstütze Krautreporter

Veröffentlicht unter Allgemein | Schreib einen Kommentar

WordPress 3.9.1: Fix für Bug mit Copy & Paste von Bildern aus Zwischenablage

Um das Problem zu beheben, muss der Konfigurationsparameter paste_data_images für den TinyMCE Editor auf true gesetzt werden. Dazu kann man folgendes tun:

In der Datei /wp-includes/class-wp-editor.php folgende Zeile ergänzen:

init["paste_data_images"] = true;

Zu finden ist die richtige Stelle dafür in diesem Code-Block (ca. Zeile 1135):

.....

/**
* Fires after tinymce.js is loaded, but before any TinyMCE editor
* instances are created.
*
* @since 3.9.0
*
* @param array $mce_settings TinyMCE settings array.
*/
     do_action( 'wp_tiny_mce_init', self::$mce_settings );

?>
<script type="text/javascript">
<?php

     if ( self::$ext_plugins )
          echo self::$ext_plugins . "\n";

     if ( ! is_admin() )
          echo 'var ajaxurl = "' . admin_url( 'admin-ajax.php', 'relative' ) . '";';

?>

( function() {
     var init, edId, qtId, firstInit, wrapper;

     if ( typeof tinymce !== 'undefined' ) {
          for ( edId in tinyMCEPreInit.mceInit ) {
               if ( firstInit ) {
                    init = tinyMCEPreInit.mceInit[edId] = tinymce.extend( {}, firstInit, tinyMCEPreInit.mceInit[edId] );
               } else {
                    init = firstInit = tinyMCEPreInit.mceInit[edId];
               }
               init["paste_data_images"] = true;

              wrapper = tinymce.DOM.select( '#wp-' + edId + '-wrap' )[0];

.....

Danach kann man wieder Bilder aus der Zwischenablage einfügen.

Veröffentlicht unter Allgemein, Web | Verschlagwortet mit | Schreib einen Kommentar

WordPress 3.9.1: Bug mit Copy & Paste von Bildern aus Zwischenablage

Anscheinden hat das heutige Update des Blog eines meiner liebsten Features gekillt: Das direkte Copy & Pasten von Bildern aus der Zwischenablage geht nicht mehr. Tolle Sache.

Siehe dazu: https://core.trac.wordpress.org/ticket/27970

Veröffentlicht unter Allgemein, Web | Verschlagwortet mit | Schreib einen Kommentar

The Voices Told Me To Do It!

1. „Create a new com.ibm.xsp.context.FacesContextExImpl!“

2. „Add all required classed to the build path!“

3. „Add a useless message to the constructor!“

4. „BUILD IT!“

5. „Open the original Jar!“

6. „In WinRAR!“

7. „Overwrite the existing classes!“

8. „Quick! Start the server!“

9. „And open a XPage!“

10. „Look! It is fulfilled!“

Veröffentlicht unter Java, XPages | Verschlagwortet mit , , , , | 7 Kommentare

Krautreporter: Nur noch 9 Tage

Zur Zeit läuft ein Experiment namens „Krautreporter„: Ein Versuch, eine neue Form des Onlinejournalismus zu etablieren und dessen derzeit desolaten Zustand zu sanieren. Vielleicht sogar ein bisschen Rebellion gegen die bestehenden Strukturen im Verlagswesen, indem die Unabhängigkeit von Journalisten wieder etwas hergestellt wird.

15.000 Unterstützer müssen monatlich 5 € investieren, um ein werbefreies und qualitativ anspruchsvolles Onlinemagazin zu finanzieren. Ohne die ständige Jagd nach Besucherzahlen durch dümmlichen Klickstrecken. Und ohne den Druck, die Werbepartner oder gar den Arbeitgeber zu vergraulen.

Gleichzeitig hört man seit Jahren, dass die meisten ja gerne bereit wären, für qualitativ hochwertigen Journalismus zu bezahlen. Und man hört auch immer die gleichen Begründungen, weshalb ein AdBlocker verwendet wird: Man möchte seine Daten schützen, man möchte nicht mit Werbung zugemüllt werden, und man würde ja spenden, wenn dies irgendwie möglich wäre. Es sollte daher eigentlich ein leichtes sein, die nötigen Anzahl an Unterstützern zusammen zu trommeln, und das Magazin zu finanzieren.

Bisher jedoch sieht es gar nicht gut aus: Noch nicht einmal die Häfte der nötigen Finanziers hat sich gefunden. Die aktuelle Ausrede ist, man könne ja nur mit Kreditkarte mitmachen. Zwar könne man eine Kreditkarten auch Prepaid erwerben, dazu müsste man jedoch an der Tankstelle vorbei. Ein bischen mehr Aktion als nur einen Mausklick. Was wahrscheinlich der gelebten Bequemlichkeit entgegensteht.

Und so scheint sich wieder einmal zu Bewahrheiten, dass es eben nur Ausreden sind: Man will gar nicht bezahlen. Man ist eigentlich mit dem Status quo zu frieden. Hauptsache, man findet wieder irgendeine scheinheilige Begründung, warum man dagegen ist.

Hier zehn Gründe, das Experiment zu unterstützen. Und hier kann man Prepaid-Kreditkarten ergattern. (Die Karte nach Nutzung einfach wegwerfen. Alternativ nie wieder benutzen. Und schon stimmt die Privatsphäre wieder).

Ich unterstütze Krautreporter

Veröffentlicht unter Allgemein | Ein Kommentar

XPages & Angular.js: Fileuploads

When using Angular.js you sooner or later want to upload a file to your Domino server. But to do this, you not only need some nice looking frontend, you also need some code in the backend. For the frontend you can use one of the already exsiting modules which are available for Angular.js, for example the angular-file-upload. For a quick start, I have choosen to modify the provided Simple example.

After stripping down the example files (just saved the whole website with Firefox), you can import all the files into a new database. Mark Roden has written a very good tutorial about the details for this step.

The WebContent folder should look like this:

Now you have to modify the index.html and make all pathes relative:

When you open the index.html in the browser you will see some errors in the console, because of some missing fonts, but we will ignore this issue in this quick example.

Instead, we are adding a link for a download of an uploaded file:

&#160;<a download="{{ item.file.name }}" ng-href="{{ item.file.dlPath }}">download</a></td>

The download link will be filled with the URL of the uploaded attachment in the target database after a successfull upload.

Now it’s time to tell the frontend where to store the file in the backend. For this, you have to modify the controller.js and define the target of the upload process. In this example, the target is a XPage named „upload.xsp„. After uploading a file to the server, the XPage returns the URL of the attachment as a JSON string. To update the link in the frontend, we bind a function to the event „success“ which adds the URL to the current file item:

angular.module('app', ['angularFileUpload'])

.controller('TestController', function ($scope, $fileUploader) {
    'use strict';

    // create a uploader with options
    var uploader = $scope.uploader = $fileUploader.create({
        scope: $scope,   
        url: 'upload.xsp'
    });

    uploader.bind('success', function (event, xhr, item, response) {
        // add the response url to the file item 
        item.file.dlPath = response.url;
    });

});

 [This is the complete controler.js which replaces the file from the module’s example.]

The XPage handles the uploaded files them directly without a file upload control. Every uploaded file will be attached to a single document, and embedded to the Richtext item „Body„. If the upload was successfull, the XPages returns the JSON data containing the URL to the newly created attachment.

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
    <xp:this.data>
        <xp:dominoDocument var="documentFile" action="editDocument" concurrencyMode="force" />
    </xp:this.data>

    <xp:this.afterRenderResponse>
        <![CDATA[#{javascript:

            /**
             * saves a uploaded attachment to a datasource
             *
             * @param ds
             *        the datasource
             * @param rtItemName
             *        the richtext item to save the file
             * @return
             *        the name of the uploaded file
             * @author Sven Hasselbach
             */
            function saveAttachment( ds:NotesXspDocument, rtItemName:String ):String {

                // get the file data
                var con = facesContext.getExternalContext();
                var request:com.sun.faces.context.MyHttpServletRequestWrapper = con.getRequest();
                var map:java.util.Map = request.getParameterMap();
                var fileData:com.ibm.xsp.http.UploadedFile = map.get( "file" );

                if( fileData == null )
                      return;

                // get the file
                var tempFile:java.io.File = fileData.getServerFile();
                var correctedFile = new java.io.File( tempFile.getParentFile().getAbsolutePath() +
                java.io.File.separator + fileData.getClientFileName() );
                var success = tempFile.renameTo(correctedFile);

                // create or use an existing RT item
                var rtFiles:NotesRichTextItem = null;
                if(!(ds.getDocument().hasItem( rtItemName ))){
                    rtFiles = ds.getDocument().createRichTextItem( rtItemName )
                }else{
                    rtFiles = ds.getDocument().getFirstItem( rtItemName );
                }

                // embed the file
                rtFiles.embedObject(lotus.domino.local.EmbeddedObject.EMBED_ATTACHMENT, "",
                      correctedFile.getAbsolutePath(), null);

                  // rename the file back for server processing
                  correctedFile.renameTo(tempFile);

                  // save the datasource
                ds.save();

                // return the filenam
                return fileData.getClientFileName();

            }

            // save the doc
            var file = saveAttachment( documentFile, "Body" );

            // create the response
            var res = facesContext.getExternalContext().getResponse();
            res.setContentType( "application/json" );
            res.setCharacterEncoding( "UTF-8" );
            var writer = res.getWriter();

            if( file != null ){
                // send a JSON url string back to the client
                var url = documentFile.getDocument().getHttpURL();
                var fileUrl = url.replace("?OpenDocument","/$File/"+file+"?OpenElement");
                writer.write( '{"url": "' + fileUrl + '"}' );    
            }else{
                // otherwise send empty JSON data
                writer.write( '{}' );
            }
            writer.flush();
            facesContext.responseComplete();
        }]]>
    </xp:this.afterRenderResponse>
</xp:view>

After uploading a file, you can see that the file was uploaded successfully in the firebug console:

When clicking the „download“ link, the file is available to download:

And the attachment was uploaded to the database:

That’s it!

Veröffentlicht unter Angular.js | Verschlagwortet mit , , , , , , | 2 Kommentare

XPages: Create a Database without Template

On stackoverflow.com, an interessting topic was asked about how to create a notes database programmatically without using a template. The problem is, that it will not contain a Icon document. But in this document are all database properties stored. So the question is: How can you create this document?

Jesse Gallagher came up with the idea to use the DXL import and create the Icon document this way, which works fine. But the next problem is, that there is no ACL note in the database and no default view.

That’s why I modified his idea and created a Java Utility class. This class creates a new database which includes all of the required design elements.

package ch.hasselba.core;

import lotus.domino.ACL;
import lotus.domino.Base;
import lotus.domino.Database;
import lotus.domino.DbDirectory;
import lotus.domino.DxlImporter;
import lotus.domino.Session;

/**
 * DB Utilities
 * 
 * @author Sven Hasselbach
 * @version 1.1
 */
public class DBUtil {

    /**
     * creates a new database 
     * the database is identically to a database created by the -blank- template in designer.
     * The default access is set to Manager
     *  
     * @param session
     *             the session used to create the database
     * @param dbTitle
     *             the database title
     * @param dbPath
     *             the path of the database
     * @param dbServer
     *             the server 
     * 
     * @version 1.1
     */
    public static void createDatabase( Session session,  final String dbTitle, final String dbPath, final String dbServer ) {
        DbDirectory dbDir = null;
        Database db = null;
        DxlImporter importer = null;
        ACL acl = null;

        try{
            // create a new database
            dbDir = session.getDbDirectory( dbServer );
            db = dbDir.createDatabase( dbPath );

            // initialize dxl importer
            importer = session.createDxlImporter();
            importer.setDesignImportOption( DxlImporter.DXLIMPORTOPTION_REPLACE_ELSE_CREATE );

            // generate DXL
            String dxl = generateDXL( dbTitle, dbPath, db.getReplicaID() );

            // import DXL
            importer.importDxl(dxl, db);

            // set ACL: Default to Manager
            acl = db.getACL();
            acl.getFirstEntry().setLevel(ACL.LEVEL_MANAGER);
            acl.save();

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            recycleObj( acl );
            recycleObj( importer );
            recycleObj( db );
            recycleObj( dbDir );
        }

    }

    /**
     * generates the DXL for a blank database
     * 
     * @param dbTitle
     *            the title of the database
     * @param dbPath
     *             the path of the database
     * @param dbReplicaId
     *             the replica of the database
     * @return    String with DXL
     * 
     * @version 1.1
     *          
     */
    private static String generateDXL( final String dbTitle, final String dbPath , final String dbReplicaId ){

        StringBuilder str = new StringBuilder();

        str.append("<?xml version='1.0' encoding='utf-8'?>");
        str.append("<!DOCTYPE database SYSTEM 'xmlschemas/domino_8_5_3.dtd'>");
        str.append("<database xmlns='http://www.lotus.com/dxl' version='8.5' maintenanceversion='3.0' ");
        str.append("replicaid='");
        str.append( dbReplicaId );
        str.append("' path='");
        str.append( dbPath );
        str.append("' title='");
        str.append( dbTitle );
        str.append("' allowstoredforms='false' ");
        str.append("usejavascriptinpages='false' increasemaxfields='true' showinopendialog='false'>");
        str.append("<databaseinfo dbid='");
        str.append( dbReplicaId );
        str.append( "' odsversion='51' ");
        str.append("numberofdocuments='0'></databaseinfo>");
        str.append("<note default='true' class='icon'>");
        str.append("<noteinfo noteid='11e'>");
        str.append("</noteinfo>");
        str.append("<item name='IconBitmap' summary='true'>");
        str.append("<rawitemdata type='6'>");
        str.append("AiAgAQAA///////wD///gAH//gAAf/wAAD/4AAAf8AAAD+AAAAfgAAAHwAAAA8AAAAPAAAADgAAA");
        str.append("AYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAHAAAADwAAAA8AAAAPgAAAH4AAAB/AAAA/4AAAf");
        str.append("/AAAP/4AAH//gAH///AP//////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAiIiIiAAAAAAAAAAAAAAI");
        str.append("jPZmZm/IgAAAAAAAAAAIjGZmZmZmZsiAAAAAAAAAjGZmZmZmZmZmyAAAAAAACMZmZmZmZmZmZmyA");
        str.append("AAAAAIxmZmZmZmZmZmZmyAAAAAjGZmZmZmZmZmZmZmyAAAAIZmbyL2byL2byL2ZmgAAAjGZmIiJm");
        str.append("IiJmIiJmZsgAAIZmZiIiZiIiZiIiZmZoAADGZmYiImYiImYiImZmbAAI9mZmIiJmIiJmIiJmZm+A");
        str.append("CGZmZiIiZiIiZiIiZmZmgAhmZmYiImYiImYiImZmZoAIZmZmIiJmIiJmIiJmZmaACGZvIiIiZiIi");
        str.append("ZiIiIvZmgAhmYiIiImYiImYiIiImZoAIZm8iIi9m8i9m8iIi9maACPZmZmZmZmZmZmZmZmZvgADG");
        str.append("ZmbyL2byL2byL2ZmbAAAj2ZmIiJmIiJmIiJmZvgAAIxmZiIiZiIiZiIiZmbIAAAI9mbyL2byL2by");
        str.append("L2ZvgAAACMZmZmZmZmZmZmZmbIAAAACMZmZmZmZmZmZmZsgAAAAACMZmZmZmZmZmZmyAAAAAAACM");
        str.append("9mZmZmZmZm/IAAAAAAAACIz2ZmZmZm/IgAAAAAAAAAAIiMZmZmyIgAAAAAAAAAAAAACIiIiIAAAA");
        str.append("AAAAUEECICABAAD/////+A4DgA==");
        str.append("</rawitemdata></item>");
        str.append("<item name='$Daos'><text>0</text></item>");
        str.append("<item name='$TITLE'><text>");
        str.append( dbTitle );
        str.append("</text></item>");
        str.append("<item name='$Flags'><text>7f</text></item>");
        str.append("<item name='$FlagsNoRefresh'><text/></item></note>");
        str.append("<view xmlns='http://www.lotus.com/dxl' version='8.5' maintenanceversion='3.0' ");
        str.append("replicaid='");
        str.append( dbReplicaId );
        str.append("' showinmenu='true' publicaccess='false' default='true' noviewformat='true'>");
        str.append("<noteinfo noteid='11a' sequence='1'></noteinfo>");
        str.append("<code event='selection'><formula>SELECT @All</formula></code>");
        str.append("<item name='$FormulaClass'><text>1</text></item></view>");
        str.append("</database>");

        return str.toString();

    }

    /**
     * recycles notes objects
     * 
     * @param obj
     *             the notes object to recycle
     */
    private static void recycleObj( Base obj ){
        try{
            if( obj != null )
                obj.recycle();
        }catch( Exception e ){}
    }
}

Here is an example XPage how to use the class:

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

    DB Path:<xp:inputText id="inputTextDBPath" value="#{viewScope.dbPath}" /><xp:br />
    DB Title:<xp:inputText id="inputText1" value="#{viewScope.dbTitle}" /><xp:br />

    <xp:button value="Create DB" id="buttonCreateDB">
        <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
            <xp:this.action>
                <![CDATA[#{javascript:
                    importPackage( ch.hasselba.core );
                    var dbUtil = new ch.hasselba.core.DBUtil();
                    dbUtil.createDatabase(session, viewScope.dbTitle, viewScope.dbPath, "");
                }]]>
            </xp:this.action>
        </xp:eventHandler>
    </xp:button>

</xp:view>

You can enter the database Title and the database path. After clicking the button „Create DB“, the database is created on the server (assuming you have the right to do that).

Veröffentlicht unter Java, XPages | Verschlagwortet mit , , , , , | 2 Kommentare

You might not need jQuery

I have found a very interesting website: You might not need jQuery. It contains a lot of usefull solutions for the different IE versions.

Veröffentlicht unter Java Script, jQuery | Verschlagwortet mit , , | Schreib einen Kommentar