cogAn API for accessing structured data with JavaScript
TypeJAR
CategoryAPI
Developed by

Yann Flory

Active Installs1
Rating
Rate!
1 Votes
LicenseGNU Lesser General Public License 2.1
Installable with the Extension Manager

Description

With this extension, you can easily access the data from your application. Among the functionalities, you can easily see, modify, add or delete items of your extension.

This extension is extending the Structured data access API.
The full documentation is available on the page of the main module.

How to use the JS API

You can use all the methods described in the Structured data access API documentation.
However, since the data is loaded from the server in a asynchronous way, you should add a last parameter callback if you want to be able to use the data.

callback : function(error, data)
error : Ajax error returned if there is any
data : the JSON representation of the Map returned by the method

Load the webjar

To use the structured data access JS API, first you have to load the webjar containing the JavaScript code:

require.config({
    paths: { "xapp": "$!services.webjars.url('org.xwiki.contrib:api-structured-data-js', 'api-structured-data.js')" }
});

require(['xapp'], function(XApp) {
 // Your code here
});
If you are using this application on XWiki < 6.3, you have to change the require.config part :
require.config({
    paths: { "xapp": "$!services.webjars.url('api-structured-data-js/0.3/extensible-api.js')" },
});
With "0.3" to replace with the version of the application you are using.

Get an application

XApp.getCurrent

 Parameters  /
 Returns An AWM app containing all the methods for accessing the application data.

XApp.getApp

 Parameters 
  • appId: The application id (see Application ID structure).
  • (optional) wiki: The name of the wiki where is located the application
 Returns An object (AWM app OR XWiki class app) containing all the methods for accessing the application data.

API

If you want details about the methods, check the Structured data access API documentation.

  • getSchema(callback)
  • getItems([Map options,] callback)
  • getItem(String itemId, [List properties,] callback)
    • storeItem(String itemId, Map itemData, callback)
    • deleteItem(String itemId, callback)
  • getItemDocument(String itemId, [List properties,] callback)
    • storeItemDocument(String itemId, Map documentData, callback)
With the JavaScript API, unlike the script service API, you can't directly get the document data from an item with :
$app.getItem("MyItem").getDocumentFields()
You have to use the specific method :
app.getItemDocument("MyItem", callback)

Example


require.config({
    paths: { "xapp": "$!services.webjars.url('org.xwiki.contrib:api-structured-data-js', 'api-structured-data.js')" }
});

require(['xapp'], function(XApp) {
 var app = XApp.getApp("Ideas", "xwiki"); /* getCurrent(), getApp(appName) and getApp(AppName, wikiName) are available */

 /* Asynchronous api */
  app.getItems({limit: 50}, function (err, result) {
   if (err) { throw err; } // Or handle somehow else...
   //Do something with result["YourItem"].yourProp
 });

  app.getItem("foo", function (err, foo) {
   if (err) { throw err; }
    foo.genre = 'drama';
    foo.releaseDate = (new Date()).getTime();
    app.storeItem("foo", foo, function (err) {
       if (err) { console.log('something went wrong ! ' + err.stack); }
    });
  });
});

Get Started : Inline JS editor

In this guide we'll improve the basic Movie Library Application created during the guide for the REST/Velocity/Groovy Structured Data Access API. If you haven't done that yet, create the application using AppWithinMinutes with the properties mentionned in the other guide.
We are going to update the sheet of the application in order to add a JavaScript inline editor : users will be able to edit the movie's properties quickly, in view mode, by double-clicking on a property.

Edition of the sheet

First, we have to edit the sheet of the "Movies" class to add an identifier for each property. The sheet is located at :

  • Movies.Code.MoviesSheet for XWiki >= 7.2
  • MoviesCode.MoviesSheet for XWiki < 7.2
    We have to add (% data-xwiki-editor-property="{propertyName}" %) before the properties displayed. We also have to add the JavaScriptExtension to the page with $xwiki.jsx.use
    To simplify the code, we won't create the inline editors for "genre", "release date" and "synopsis" since they can't be easily represented by a String. You can try to improve this example by adding the code necessary to manage a date, a list and a long text property.
{{velocity}}
{{html wiki="true"}}
#set ($discard = $doc.use('Movies.Code.MoviesClass'))
#set ($discard = $xwiki.jsx.use('Movies.Code.MoviesSheet'))
(% class="xform" %)
(((
  ; <label for="Movies.Code.MoviesClass_0_name">$escapetool.xml($doc.displayPrettyName('name', false, false))</label>
  : (% data-xwiki-editor-property="name" %)$doc.display('name')
  ; <label for="Movies.Code.MoviesClass_0_genre">$escapetool.xml($doc.displayPrettyName('genre', false, false))</label>
  : $doc.display('genre')
  ; <label for="Movies.Code.MoviesClass_0_director">$escapetool.xml($doc.displayPrettyName('director', false, false))</label>
  : (% data-xwiki-editor-property="director" %)$doc.display('director')
  ; <label for="Movies.Code.MoviesClass_0_releaseDate">$escapetool.xml($doc.displayPrettyName('releaseDate', false, false))</label>
  : $doc.display('releaseDate')
  ; <label for="Movies.Code.MoviesClass_0_synopsis">$escapetool.xml($doc.displayPrettyName('synopsis', false, false))</label>
  : $doc.display('synopsis')
  ; <label for="Movies.Code.MoviesClass_0_ratings">$escapetool.xml($doc.displayPrettyName('ratings', false, false))</label>
  : (% data-xwiki-editor-property="ratings" %)$doc.display('ratings')
)))
{{/html}}
{{/velocity}}

Add JS to the sheet

Now, we can start working on the editor, and to do so, we are going to add a JavaScriptExtension object to the sheet. It should be used On demand only and the content must be parsed.
First, we have to load the API and get the application object : 

require.config({
    paths: {
     "xapp": "$!services.webjars.url('org.xwiki.contrib:api-structured-data-js', 'api-structured-data.js')",
    }
});

require(['xapp', "$xwiki.getDocument('Displayer.DisplayEditorJS').getURL('jsx')", 'jquery', 'xwiki-meta'], function(XApp, DSP, $, xm) {

 // Get the "Movies" application from the API
 var app = XApp.getCurrent();
 
 // Insert the end of the code here

});

Then, we have three main actions to handle :

  • Open the inline editor when a user double-click on a property.
  • Save the new value in XWiki when the user presses Enter. We will use the "storeItem" method from the API here!
  • Display the new value and hide the editor.
    We will also make sure that when a user clicks on the page but not on a property, all opened editors are closed so that the user has a way to cancel the edition easily.
    Here is the complete code :
require.config({
    paths: {
     "xapp": "$!services.webjars.url('org.xwiki.contrib:api-structured-data-js', 'api-structured-data.js')",
    }
});

require(['xapp', "$xwiki.getDocument('Displayer.DisplayEditorJS').getURL('jsx')", 'jquery', 'xwiki-meta'], function(XApp, DSP, $, xm) {

 // Get the "Movies" application from the API
 var app = XApp.getCurrent();

 // Open the editor when the user double clicks on a property
 var openEditor = function(e) {
   // Get the parent container
   var container = $(this).parent();
   var property = $(this).attr('data-xwiki-editor-property');
   var currentValue = $(this).text();
   // Add the editor if it doesn't exists
   if(!$(container).find(".data-xwiki-property-edit").length) {
      $(container).append('<span class="data-xwiki-property-edit"><input type="text" id="inlineEditor-'+property+'" value="'+currentValue+'" /></span>');
      $(container).find('.data-xwiki-property-edit').on('click', stopPropagation);
    }
    $(this).hide();
    $(container).find(".data-xwiki-property-edit").show();
   var input = $(container).find(".data-xwiki-property-edit input");
    $(input).focus();
   // Add the keydown event to save the field when the user presses Enter
   $(input).on('keydown', saveEditor(property));
  }
  $('span[data-xwiki-editor-property]').on('dblclick', openEditor);

 // Save the new value of the selected property
 var saveEditor = function(prop) {
   return function(e) {
     // Save if the user presses Enter (keyCode = 13)
     if(e.keyCode == 13) {
       var newValue = $('#inlineEditor-'+prop).val();
       // Create the object which will be sent to the REST resource
       var json = {};
        json[prop] = newValue;
       var itemId = XWiki.currentPage;
        app.storeItem(itemId, json, displayNewValue(prop, newValue));
      }
    }
  }

 // Display the new value and hide the editor after the save
 var displayNewValue = function(prop, newValue) {
   return function(error, data) {
     if(error) {throw error;}
     // Get the view block
     var viewElmt = $('span[data-xwiki-editor-property="'+prop+'"]');
     var editElmt = $(viewElmt).parent().find('.data-xwiki-property-edit');
      $(viewElmt).text(newValue);
      $(viewElmt).show();
      $(editElmt).hide();
    }
  }

 // Close all editors when the user clicks elsewhere on the page
 var closeAllEditors = function() {
    $('span[data-xwiki-editor-property]').show();
    $('.data-xwiki-property-edit').hide();
  }
  $('html').click(closeAllEditors);
 var stopPropagation = function(e) {e.stopPropagation();};

});

Prerequisites & Installation Instructions

We recommend using the Extension Manager to install this extension (Make sure that the text "Installable with the Extension Manager" is displayed at the top right location on this page to know if this extension can be installed with the Extension Manager). Note that installing Extensions when being offline is currently not supported and you'd need to use some complex manual method.

You can also use the manual method which involves dropping the JAR file and all its dependencies into the WEB-INF/lib folder and restarting XWiki.

Dependencies

Dependencies for this extension (org.xwiki.contrib:api-structured-data-js 0.5):

Tags:
Created by Yann Flory on 2016/01/14 11:22
    

Get Connected