XWiki JavaScript API

JavaScript Events

XWiki JavaScript event names have the following syntax: xwiki:modulename:eventname, like for instance:

document.observe("xwiki:modulename:eventname", function(event) {
//
 doSomething();

// The event can have an option memo object to pass to its observers some information:
 console.log(event.memo.somethingINeedToKnow);
});

JavaScript event handlers are used to verify user input and actions or browser actions in order to choose the action to execute on page load, when the page is closed or when the user clicks a button or sends an input data.

XWiki DOM Events

XWiki DOM events are defined in the resources/js/xwiki/xwiki.js file.

  • xwiki:dom:loaded is similar to the Prototype dom:loaded event with the sole difference that in the time-lapse between dom:loaded and xwiki:dom:loaded, XWiki may have transformed the DOM. As a general rule, it is recommended to bind startup scripts to xwiki:dom:loaded instead of window.load or to document.dom:loaded, mostly because this event is meant for code to be notified of loading of the XWiki-transformed version of the initial DOM.

Example: A XWiki JavaScript extension used by "XWiki.XWikiSyntax" in order to load the proper documentation, depending on the syntax selected in the drop-down list.


document.observe('xwiki:dom:loaded', function() {
 if($('goto-select')) {
    Event.observe($('goto-select'), 'change', function (event) {
      var select = event.element();
      var i = select.selectedIndex;
     if (window.location != select.options[i].value) {
        window.location = select.options[i].value;
      }
    });
    $('goto-select').next().hide();
  }
});
  • xwiki:dom:loading is sent between dom:loaded and xwiki:dom:loaded, before XWiki changes the DOM. This is the event that should start all scripts making important DOM changes that other scripts should see. 
  • xwiki:dom:updated is sent whenever an important change in the DOM occurs, such as loading new content or refreshing the document content. Scripts that add behavior which enhance the DOM should listen to this event as well and re-apply their initialization process on the updated content. 

Example: change notification in the annotation list followed by a tab reload.

// Notify the content change.
document.fire('xwiki:dom:updated', {elements: [this.annotatedElement]});
// and also handle the tab 'downstairs' when the annotations list changes
this.reloadTab(navigateToPane);

Deferred Scripts

When the script is loaded deferred, the XWiki DOM events might be triggered before your script is executed and is able to observe these events. To prevent this situation, you should check whether the following flags are true:

  • XWiki.isInitialized before waiting for wiki:dom:loading
  • XWiki.domIsLoaded before waiting for xwiki:dom:loaded

Examples:


var init = function() {
//...
};

// When the document is loaded, install search suggestions
(XWiki.isInitialized && init()) || document.observe('xwiki:dom:loading', init);
return XWiki;
function init(){
//...
}

(XWiki.domIsLoaded && init()) || document.observe('xwiki:dom:loaded', init);
return XWiki;

actionButtons.js

actionButtons.js is a JavaScript resource available under /xwiki/resources/js/xwiki/actionbuttons and defines document content events and action events for Form buttons:

Document Content Events

  • xwiki:document:saved is sent after the document has been successfully saved in an asynchronous request like for instance after clicking on "Save and Continue".

Example: The attachment selector

if (!hasErrors) {
 if (this.directSave) {
    uploadForm.submit();
  } else {
    document.observe('xwiki:document:saved', function() {
      new XWiki.widgets.Notification("$services.localization.render('xe.attachmentSelector.upload.inProgress')", 'inprogress');
      uploadForm.submit();
    })
    document.fire('xwiki:actions:save', {'continue': true, form: this.property.up('form')});
}
  • xwiki:document:saveFailed is sent when a save and continue attempt failed for some reason. 

Action Events

  • xwiki:actions:cancel is sent after the user clicks the "Cancel" button of an editor but before actually cancelling the edit.

Example: The automatic save feature

createUIElements : function() {
//...

// When hitting cancel, the form isn't submitted anymore, instead the location is changed directly. In order to fix
// the fastback problem above for Cancel, we need to also listen to this event:
document.observe("xwiki:actions:cancel", function() {
container.remove();
});
},
  • xwiki:actions:beforePreview was introduced starting with version 7.4.1 and it is sent after the user clicks the "Preview" button in edit mode, but before the edit form is validated. This event can be used to update form fields before they are submitted to the "preview" action.
  • xwiki:actions:preview is sent after the user clicks the "Preview" button of an editor but before actually leaving the edit mode.
  • xwiki:actions:beforeSave was introduced since version 7.4.1 and is sent after the user clicks the "Save" or "Save & Continue" button in edit mode but before the edit form is validated. This event can be used to update form fields right before they are submitted to the "save" action.
  • xwiki:actions:save is sent after the user clicks the "Save" or "Save & Continue" button of an editor but before actually submitting the form.

Example

function init() {
//...
document.observe('xwiki:actions:save', function(event) {
  document.fire('xwiki:inline:save', {originalEvent: event});
  }.bindAsEventListener(window));
 return XWiki;
}(XWiki || {}));
While most properties can be accessed as event.memo.property, this doesn't work with event.memo.continue because continue is a reserved keyword.

Document Extra Events

Document Extra Events are defined in xwiki.js which is stored under /xwiki/resources/js/xwiki/:

  • xwiki:docextra:loaded is fired upon reception of the content of a document footer tab by AJAX. This event is useful if you need to operate transformations of the received content. You can filter on which tab content to operate using the event memo. The DOM element in which the retrieved content has been injected is also passed to facilitate transformations.

Example: Add the delete, edit and validate listeners to the annotations in the annotations tab when the extra panels are loaded.

document.observe('xwiki:docextra:loaded', this.addDeleteListenersInTab.bindAsEventListener(this));
document.observe('xwiki:docextra:loaded', this.addEditListenersInTab.bindAsEventListener(this));
document.observe('xwiki:docextra:loaded', this.addValidateListenersInTab.bindAsEventListener(this));
  • xwiki:docextra:activated is fired upon activation of a tab. This event sends a notification for each tab activation, just after the tab content is actually made visible. 

Example:

/**
  * Method used by docextra.vm to emulate tabbed panes.
  *
  * @param extraID Id of the pane to show.
  * @param extraTemplate Velocity template to retrieve and display in the pane.
  * @param scrollToAnchor Jump to the pane anchor.
  * @return
*/

displayDocExtra: function (extraID, extraTemplate, scrollToAnchor) {
 // Nested function: hides the previously displayed extra pane (window.activeDocExtraPane)
 // and display the one that is passed as an argument (extraID).
 // Fires an event to notify that the pane has changed.
 var dhtmlSwitch = function(extraID) {
 var tab = document.getElementById(extraID + "tab");
 var pane = document.getElementById(extraID + "pane");
 if (window.activeDocExtraTab != null) {
  window.activeDocExtraTab.className="";
  window.activeDocExtraPane.className="hidden";
  }
  window.activeDocExtraTab = tab;
  window.activeDocExtraPane = pane;
  window.activeDocExtraTab.className="active";
  window.activeDocExtraPane.className="";
  tab.blur();
  document.fire("xwiki:docextra:activated", {"id": extraID});
};

Annotation Events

Annotation events are defined in the "XWiki.JavaScriptExtension" objects attached to "AnnotationsCode.Script" and "AnnotationsCode.Settings":

  • xwiki:annotations:filter:changed
  • xwiki:annotations:settings:loaded

Full-screen Events

Full-screen events are defined in fullScreen.js which is stored under xwiki/resources/uicomponents/widgets/:

  • xwiki:fullscreen:enter
  • xwiki:fullscreen:entered
  • xwiki:fullscreen:exit
  • xwiki:fullscreen:exited
  • xwiki:fullscreen:resized

Livetable Events

Livetable events are defined in livetable.js which is stored under /xwiki/resources/js/xwiki/table/:

  • xwiki:livetable:newrow 

App Within Minutes example:

document.observe('xwiki:livetable:newrow', function(event) {
 // Add the xredirect parameter to the query string of the delete action to
 // redirect the user back to the live table after an application is deleted.
  var deleteLink = event.memo.row.down('td.actions').down('a.actiondelete');
  deleteLink.href = deleteLink.href + '&xredirect=' + encodeURIComponent(window.location.href);
});

As you can see in the above code, event.memo.row holds the new row.

  • xwiki:livetable:loadingEntries
  • xwiki:livetable:receivedEntries - event.memo.data contains the received JSON data
  • xwiki:livetable:loadingComplete - event.memo.status contains the response status code
  • xwiki:livetable:displayComplete
  • xwiki:livetable:ready
  • xwiki:livetable:loading

Example

if ((typeof(XWiki) != 'undefined') && (typeof(XWiki.widgets) != 'undefined') && (typeof(XWiki.widgets.LiveTable) != 'undefined')) {
  startup();
  } else {
  document.observe('xwiki:livetable:loading', startup);
}

The livetable also sends specific events containing the table name on the third position, such as xwiki:livetable:${tableName}:loadingEntries. The generic event has the table name in the memo, as event.memo.tableId.

"macros.vm" example

#if ($hasPageSize)
  document.observe("xwiki:livetable:${divid}:loadingEntries", function() { $('${divid}-pagesize').addClassName("hidden"); } );
  document.observe("xwiki:livetable:${divid}:loadingComplete", function() { $('${divid}-pagesize').removeClassName("hidden"); } );
#end

Wysiwyg Events

The Wysiwyg JavaScript API is available in the file XWikiWysiwyg.js and it is stored on your filesystem under js/xwiki/wysiwyg/xwe/.

  • xwiki:wysiwyg:created is fired after a WYSIWYG editor is successfully created.
  • xwiki:wysiwyg:loaded is fired after a WYSIWYG editor is successfully loaded.
  • xwiki:wysiwyg:showingWysiwyg is fired when the WYSIWYG tab was clicked and the rich text area is about to be reloaded.
  • xwiki:wysiwyg:showWysiwyg is fired after the WYSIWYG tab was loaded.
  • xwiki:wysiwyg:showingSource is fired when the Source tab was clicked and the source text area is about to be reloaded.
  • xwiki:wysiwyg:showSource

RequireJS and jQuery APIs

By default, XWiki Standard uses PrototypeJS which is bound to the $ symbol. In order to use jQuery, you may require it using the RequireJS AMD standard as follows:

require(['jquery'], function ($) {
    $('#xwikicontent').append('<p>Inside of this function, $ becomes jquery!</p>');
});
Scripts loaded using require are executed asynchronously. If they are not required, they are never loaded at all.

Bridge Custom XWiki Events Between Prototype and jQuery

Starting with version 6.4 you can catch from jQuery the custom XWiki events that are fired from Prototype using the code below:

require(['jquery', 'xwiki-events-bridge'], function($) {
  $('.some-element').on('xwiki:moduleName:eventName', function(event, data) {
   // Here, do something that will be executed at the moment the event is fired.
    doSomething();

   // The passed data is a reference to the event.memo from Prototype.
    console.log(data.somethingINeedToKnow);
  });
});

Since version 7.1, the event listeners registered from Prototype are notified each time a custom XWiki event is fired using the jQuery API. 

// Prototype (old code that you don't have time to rewrite)
document.observe('xwiki:dom:updated', function(event) {
 event.memo.elements.each(function(element) {
   // Do something.
 });
});
...
// jQuery (new code, in a different file/page)
require(['jquery', 'xwiki-events-bridge'], function($) {
 $(document).trigger('xwiki:dom:updated', {'elements': $('.some-container').toArray()});
});

Retrieve Meta Information about the Current Document

For this purpose, you can use the AMD module as follows:

require(['xwiki-meta'], function (xm) {
  xm.documentReference  // since 7.3M2 is used to get the reference of the current document as a DocumentReference object
  xm.document           // get the current document (eg: Main.WebHome) -- deprecated since 7.3M2, use documentReference instead
  xm.wiki               // get the current wiki (eg: xwiki)            -- deprecated since 7.3M2, use documentReference instead
  xm.space              // get the current space (eg: Main)            -- deprecated since 7.3M2, use documentReference instead
  xm.page               // get the current page name (eg: WebHome)     -- deprecated since 7.3M2, use documentReference instead
  xm.version            // get the current document version
  xm.restURL            // get the REST URL of the current doc (eg: /xwiki/rest/wikis/xwiki/spaces/Main/pages/WebHome)
  xm.form_token         // get the current CSRF token that you should pass to your scripts to avoid CSRF attacks.
});

Entity References

The JavaScript API for entity references is available on GitHub.

To resolve and serialize Entity References on the client side, use this script:

var documentReference = XWiki.Model.resolve('wiki:Space.Page', XWiki.EntityType.DOCUMENT);
var attachmentReference = new XWiki.AttachmentReference('logo.png', documentReference);
XWiki.Model.serialize(attachmentReference);

Starting with version 7.2, the XWiki.Model JavaScript API supports nested spaces for which you can resolve the Entity Reference as follows:

var documentReference = XWiki.Model.resolve('wiki:Path.To.My.Page', XWiki.EntityType.DOCUMENT);
documentReference.getReversedReferenceChain().map(function(entityReference) {
 return entityReference.type + ': ' + entityReference.name
}).join()

// Will produce:
// 0: wiki,1: Path,1: To,1: My,2: Page

Additionally, you may pass a "provider" as the third argument to XWiki.Model.resolve() which will be used to fill the missing references. The provider can be a function that gets the entity type, an array of entity names or an entity reference.

var documentReference = XWiki.Model.resolve('Page', XWiki.EntityType.DOCUMENT, function(type) {
 switch(type) {
   case: XWiki.EntityType.WIKI:
     return 'wiki';
   case: XWiki.EntityType.SPACE:
     return 'Space';
    default:
     return null;
  }
});
// Produces wiki:Space.Page

var documentReference = XWiki.Model.resolve('Page', XWiki.EntityType.DOCUMENT, ['wiki', 'Space']);
// Same output

var spaceReference = new XWiki.SpaceReference('wiki', 'Space');
var documentReference = XWiki.Model.resolve('Page', XWiki.EntityType.DOCUMENT, spaceReference);
// Same output

In order to construct a Reference to Nested Spaces, a new equals() method has been added:

// Construct a Nested Space reference
var reference = new XWiki.SpaceReference('wiki', ['space1', 'space2']);
expect(XWiki.Model.serialize(reference)).toEqual('wiki:space1.space2');
reference = new XWiki.DocumentReference('wiki', ['space1', 'space2'], 'page');
expect(XWiki.Model.serialize(reference)).toEqual('wiki:space1.space2.page');
// Construct a non-Nested Space reference
reference = new XWiki.SpaceReference('wiki', 'space');
expect(XWiki.Model.serialize(reference)).toEqual('wiki:space');
// Try passing non-valid space parameters
expect(function() {new XWiki.SpaceReference('wiki', [])}).toThrow('Missing mandatory space name or invalid type for: []');
expect(function() {new XWiki.SpaceReference('wiki', 12)}).toThrow('Missing mandatory space name or invalid type for: [12]');

// Equals() examples
var reference1 = new XWiki.DocumentReference('wiki', ['space1', 'space2'], 'page');
var reference2 = new XWiki.DocumentReference('wiki', ['space1', 'space2'], 'page');
var reference3 = new XWiki.DocumentReference('wiki2', ['space1', 'space2'], 'page');
expect(reference1.equals(reference2)).toBe(true);
expect(reference1.equals(reference3)).toBe(false);

Finally, XWiki has introduced a new XWiki.EntityReferenceTree class which partially mimics the Java EntityReferenceTree on JS side in order to easily use a serialized Java EntityReferenceTree. For instance:

this.entities = XWiki.EntityReferenceTree.fromJSONObject(transport.responseText.evalJSON());

       

Related Pages

Search this space

 

Most popular tags

Failed to execute the [groovy] macro
  1. access rights
  2. activity stream
  3. annotation
  4. attachment
  5. comment
  6. Document Tree Macro
  7. export
  8. Extension Manager
  9. Flamingo skin
  10. global user
  11. Groovy event listener
  12. group
  13. nested page
  14. search
  15. skin
  16. syntax
  17. user
  18. user profile
  19. velocity macros
  20. wiki
  21. wysiwyg
  22. XWiki Applications
  23. xwikiattachment_archive table
  24. xwikiattachment table
  25. xwikiattrecyclebin table
  26. xwikiproperties table

[Display all tags from this space]