Documentation Center

How to prevent structure changes using the API

Ensure users can only edit specific parts of the document by using the API and without changing the schema.

In some cases, you can prevent authors from editing parts of the document by modifying the schema. This method is explained in a separate topic: Mark parts of the document as non-editable in the schema.

In other cases you still want to prevent authors from editing parts of the document but need another approach, such as using the Content Editor API for this goal. For instance, if you have documents with two kinds of tables- some tables which users can add or modify, but other tables which users can only change/add text content within the table. Changing the XML schema is not feasible as you would have to have a separate schema for each table configuration.

An example of using the API to prevent structure change

In this case, with two types of tables, you can use the Content Editor API to prevent all changes to those particular elements without changing your XML schema. You can include the following code using a javascript reference.
// These elements and their element children can't be changed.
var immutableNames = { table: 1, tbody: 1, tr: 1 };

// These elements can't be changed, but children can be moved, deleted and added.
var immutableContainerNames = { td: 1, th: 1 };

Editor.addEventListener("load", loadHandler); 

function loadHandler(evt) {  
  evt.document.addEventListener("XopusBeforeSubtreeModified", immutable);
  evt.document.addEventListener("XopusBeforeNodeSplit", immutableContainer);
  evt.document.addEventListener("XopusBeforeNodeMerged", immutableContainer);
}

function immutable(evt) {  
  if (evt.target.getLocalName() in immutableNames)
    throw new Editor.RevertingException;
}

function immutableContainer(evt) {
  if (evt.target.getLocalName() in immutableContainerNames)
    throw new Editor.RevertingException;
}

All element names in immutableNames are completely immutable because the XopusBeforeSubtreeModified event is fired for changes that involve the event target and changes to the childNodes collection of the event target (like , insertBefore and removeChild appendChild).

All elements names in immutableContainerNames cannot be split or merged. We need to listen to these events because for those operations the target is a split or merged node, so our test in the immutable function will not cover those cases. The cases where immutableContainer elements are removed are covered by the immutable function.

Preventing changes to structures that are not built up of multiple levels of elements is left as exercise for the reader.

Hiding elements in the user interface

The API code will prevent structure changes, but it will not hide the blocked actions from the user interface. To make the interface easier to understand for the user, you can hide certain elements from the user interface by giving those elements the hidden-from-ui role. This will hide elements from the insert, delete and move menus, but not from the status bar. You can add the following elements to the roleMapping element in your configuration:

<x:element name="table" role="hidden-from-ui" />
<x:element name="tbody" role="hidden-from-ui" />
<x:element name="tr"    role="hidden-from-ui" />
<x:element name="th"    role="hidden-from-ui" />
<x:element name="td"    role="hidden-from-ui" />