User defined (custom) blocks
In order to define your own blocks without having to modify and build the front-end you can just update the following 2 files:
./Examples/CustomModules/user.json ./Examples/CustomModules/user.sjs
Block interfaces definition: It’s used to display the block and its inputs/outputs
./Examples/CustomModules/user.json
This example describes an Object block. In Pipes 2.0 this is not needed anymore, you can achieve the same using a “reverse” source block (fields in, node out with the root toggle on false).
Add a new block definition in the array like this:
[
{
"functionName": "Object",
"blockName": "Object",
"library": "user",
"events": {
"onConfigure": "let v = this.widgets[0].value;if (this.widgets.length == (parseInt(v) + 1)) return; this.widgets=this.widgets.slice(0,1);for (let x=0;x < v ;x++) {this.addWidget(\"text\", \"key\" + x , this.widgets_values[x+1], function (v) {})};return;"
},
"inputs": [
{
"name": "var0",
"type": null
}
],
"properties": [
],
"widgets": [
{
"type": "text",
"name": "nbKeys",
"default": "1",
"values": "1",
"callback": "let nb = this.inputs.length;let vInt = parseInt(v); if (vInt < nb) {for (let i=0;i<(nb - vInt);i++){this.removeInput(this.inputs.length-1);this.widgets.pop()}}else if (vInt > nb) { this.widgets=this.widgets.slice(0,1 + nb);for(let i=nb;i<vInt;i++) {this.addInput('var' + i,null);this.addWidget(\"text\", \"key\" + i , '', function (v) {})};}"
},
{
"type": "text",
"name": "key0",
"default": "",
"values": []
}
],
"outputs": [
{
"name": "obj0",
"type": null
}
],
"function": {
"ref": null,
"code": ""
}
}
]
Block implementation :
It’s used to execute the logic of the block in MarkLogic
The code is located in :
./Examples/CustomModules/user.sjs
function init(LiteGraph){
function ObjectBlock() {
this.addInput("var0");
this.nbKeys = this.addWidget("text","nbKeys", "string", function(v){}, { } );
const OUTPUTS = 20;
for (let vp = 0; vp < OUTPUTS; vp++ ) {
var varName = 'key' + vp;
this[varName] = this.addWidget("text",varName, "", function(v){}, { } );
this.addInput("var" + vp);
}
}
ObjectBlock.title = "Object";
// New in Pipes 2: This should be fixed on "user.sjs", that is this file.
ObjectBlock.prototype.getRuntimeLibraryPath = function() {
return "user.sjs";
}
// New in Pipes 2: This returns the method name which should be in the
// getRuntimeLibraryPath() module.
ObjectBlock.prototype.getRuntimeLibraryFunctionName = function() {
return "executeObjectBlock";
}
/*
Old Pipes 1.x implementation for reference.
ObjectBlock.prototype.onExecute = function() {
let obj = {};
let keys = parseInt(this.nbKeys.value);
for ( let i = 0 ; i < keys ; i++ ) {
const key = this['key'+i].value;
if ( key && key.length > 0 ) {
obj[key] = this.getInputData(i);
}
}
this.setOutputData(0,obj);
}
*/
// This should be fixed to this. In case of interpretation, executeBlock will call the delegate.
ObjectBlock.prototype.onExecute = function() {
require("/custom-modules/pipes/runtime/coreFunctions.sjs").executeBlock(this);
}
LiteGraph.registerNodeType("user/Object", ObjectBlock );
}
// BEWARE, this is outside the object:
// Optional function named <executionMethod>InputAsList.
// If not present: false.
// Return true if you want to get the inputs as a list (executeMethod(propertiesAnmdWidgets,inputsAsLost)
// Return false if you want the inputs as args: (executeMethod(propertiesAnmdWidgets,inp1,inp2,inp3)
//
function executeObjectBlockInputAsList() {
return true;
}
// Optional function named <executionMethod>ReturnAlwaysAnArray.
// If not present: false
// Return true: <executionMethod> should always return [output1,output2,output3...]
// Return false: If nr of outputs = 1 -> return output, if outputs > 1 return [output1,output2,....]
function executeObjectBlockReturnAlwaysAnArray() {
return false;
}
// This is the execution block
function executeObjectBlock(propertiesAndWidgets,inputs) {
let obj = {};
let keys = parseInt(propertiesAndWidgets.widgets.nbKeys);
for ( let i = 0 ; i < keys ; i++ ) {
const key = propertiesAndWidgets.widgets['key'+i];
if ( inputs && key && key.length > 0 && i < inputs.length ) {
obj[key] = inputs[i];
}
}
return obj;
}
// BE SURE to export it, else it is not visible.
module.exports = {
init:init,
executeObjectBlock,
executeObjectBlockInputAsList,
executeObjectBlockReturnAlwaysAnArray
};
You must then run gradle mlloadmodules You can also find details on block implementation here: Litegraph guides
How to tell Pipes to use these blocks
- Put these files in a separate directory. Don’t put them in the src/ directory of your DHF project. For instance, if your DHF project is in
/usr/dev/my-dhf-project
, create a folder/usr/dev/my-dhf-project/user-modules
and put the files there - Now, to tell Pipes you want to include the user blocks defined in these files, you have to use the
customModulesRoot
property. There are 2 ways to do it:java -jar marklogic-pipes-1.2-release.jar --customModulesRoot=/usr/dev/my-dhf-project/user-modules
- Or, put
customModulesRoot=/usr/dev/my-dhf-project/user-modules
in application.properties. The application.properties file should be put in the same folder from which you’re running the Pipes jar so that it can be read in on start.
- In the Pipes blocks menu, you should now see a “user” group. If you don’t see it, you probably have to refresh your browser or even clear the browser history: