Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New dependency system; added copy function to array action bar #683

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
<a href='https://ko-fi.com/J3J36TFV' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>

# Alpaca - Modified version - New features added

- A Copy function for arrays. A new icon is added to the toolbar that copies
the current element.

- New dependency system. Dependencies are specified as part of the options json, using the field "x\_dependencies". x\_dependencies is an array of objects, with the following fields:
- "field" : path to field that is to be checked (no leading slash). Use "[]" to indicate all elements of an array.
- "values": array of values against which _field_ is checked.
- "enables": array of relative paths to fields that are to be enabled when _field_ is equal to one of the values. The path root is the parent of the element indicated by _field_. So, dependencies can refer to siblings of the _field_ element, or to elements deeper in the tree. "[]" can again be used to specify all elements of an array.

Example.
```
{
"options": {
"x_dependencies": [
{
"field": "questions[]/type",
"values": ["likert","vas"],
"enables": [ "desc/nld_nld/anchors", "range"]
}
]
}
}
```
This checks if the _type_ field of each element of the _questions_ array is equal to either of the two given strings. If true, the _range_ field in the same element and the *desc.nld_nld.anchors* subfields are enabled. If false, they are disabled (hidden).

# Alpaca - JSON Forms for jQuery and Bootstrap

Alpaca provides the easiest and fastest way to generate interactive forms for the web and mobile devices.
Expand Down
1 change: 1 addition & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ var paths = {
"src/js/ControlField.js",
"src/js/ContainerField.js",
"src/js/Form.js",
"src/js/PathBasedDependencies.js",

// cache implementations
"src/js/cache/memory.js",
Expand Down
2 changes: 2 additions & 0 deletions src/js/Alpaca.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,8 @@
_resetInitValidationError(field);
}

// Dependency management is performed as a postrender call
Alpaca.PathBasedDependencies.postRenderCallback(field);
if (renderedCallback)
{
renderedCallback(field);
Expand Down
140 changes: 140 additions & 0 deletions src/js/PathBasedDependencies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
(function() {
Alpaca.PathBasedDependencies = (function() {

//var registry = {};

return {

postRenderCallback: function(control) {
if (!control.options.x_dependencies) return;
var deps = control.options.x_dependencies;
control.on("change", function() {
var deps = this.options.x_dependencies;
Alpaca.PathBasedDependencies.updateDeps(deps,this,
Alpaca.PathBasedDependencies.processDepLeaf);
});
Alpaca.PathBasedDependencies.doRecursive(control, function(current) {
current.on("add",function() {
//console.log("########ADD EVENT");
Alpaca.PathBasedDependencies.updateDeps(deps,control,
Alpaca.PathBasedDependencies.processDepLeaf);
});
current.on("move",function() {
//console.log("########ADD EVENT");
Alpaca.PathBasedDependencies.updateDeps(deps,control,
Alpaca.PathBasedDependencies.processDepLeaf);
});
});
// now, run it once to initialize
Alpaca.PathBasedDependencies.updateDeps(deps,control,
Alpaca.PathBasedDependencies.processDepLeaf);
},

// call callback(element) on current and all of its children
doRecursive: function(current,callback) {
callback(current);
if (!current.children) return;
for (var i=0; i<current.children.length; i++) {
Alpaca.PathBasedDependencies.doRecursive(current.children[i],callback);
}
},

// Update all dependencies. Call on onChange or onAdd
// deps - array of dependencies: {field, values, enables}
// field - path to source field
// values - array of source field values
// enables - array of relative paths to element(s) to enable
// when source field matches one of the values
updateDeps: function(deps,rootelem,callback) {
for (var i=0; i<deps.length; i++) {
var dep = deps[i];
//console.log("###########START "+JSON.stringify(dep));
var pathArray = dep.field.split('/');
Alpaca.PathBasedDependencies.processDep(dep,pathArray,rootelem,callback);
}
},

// process one dependency (recursive function). Can be used to traverse
// field path or enables path.
// dep - dependency (see updateDeps)
// pathArray - elements of field path
// current - top level alpaca element that matches top of pathArray
// callback - function to call on leaves
processDep: function(dep,pathArray,current,callback) {
pathArray = pathArray.slice(0); // clone
if (pathArray.length == 0) {
// leaf -> check dependency
if (typeof current == "undefined") return;
if (!current) return;
callback(dep,current);
return;
}
var name = pathArray.shift();
var isArray=false;
var z = name.indexOf("[]");
if (z >= 0) {
name = name.substring(0,z);
isArray=true;
}
//console.log(name+"#"+isArray+"$");
current = current.childrenByPropertyId[name];
if (!isArray) {
Alpaca.PathBasedDependencies.processDep(dep,pathArray,current,callback);
} else {
//console.log("array size "+current.children.length);
for (var j=0; j<current.children.length; j++) {
Alpaca.PathBasedDependencies.processDep(dep,pathArray,current.children[j],callback);
}
}
},

// process dependency of field leaf, check if field matches any of the values.
processDepLeaf: function(dep,current) {
//console.log("leaf="+current.getValue());
//console.log(current);
// check if value matches one of the possible values
for (var i=0; i<dep.values.length; i++) {
if (current.getValue() == dep.values[i]) {
for (var j=0; j<dep.enables.length; j++) {
Alpaca.PathBasedDependencies.processDepLeafEnable(true,dep.enables[j],current.parent,
Alpaca.PathBasedDependencies.enableField);
}
return;
}
}
// no match -> disable
for (var j=0; j<dep.enables.length; j++) {
Alpaca.PathBasedDependencies.processDepLeafEnable(false,dep.enables[j],current.parent,
Alpaca.PathBasedDependencies.enableField);
}
},

// traverse path to enable/disable leaves
processDepLeafEnable: function(enable,dep,current,callback) {
var pathArray = dep.split('/');
Alpaca.PathBasedDependencies.processDep(enable,pathArray,current,callback);
},

// enable/disable leaf field
enableField: function(enable,current) {
//console.log(enable ? "###ENABLE" : "$$$DISABLE");
current.getFieldEl().context.style.display = enable ? "" : "none";
if (!enable) {
/* Do not clear values for now.
// clear value when disabled
current.setDefault();
// also clear values of children
Alpaca.PathBasedDependencies.doRecursive(current, function(cur) {
cur.setDefault();
});
// TODO empty arrays (setDefault on array does not empty it)
*/
}
//console.log(current);
},

}

})();

})();
44 changes: 44 additions & 0 deletions src/js/fields/basic/ArrayField.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,17 @@
});
}
});
applyAction(self.actionbar.actions, "copy", {
"label": self.getMessage("addButtonLabel"),
"action": "copy",
"iconClass": self.view.getStyle("addIcon"),
"click": function(key, action, itemIndex) {

self.handleActionBarCopyItemClick(itemIndex, function(item) {
// done
});
}
});
applyAction(self.actionbar.actions, "remove", {
"label": self.getMessage("removeButtonLabel"),
"action": "remove",
Expand Down Expand Up @@ -1218,6 +1229,39 @@
});
},

handleActionBarCopyItemClick: function(itemIndex, callback)
{
var self = this;

self.resolveItemSchemaOptions(function(itemSchema, itemOptions, circular) {

// we only allow addition if the resolved schema isn't circularly referenced
// or the schema is optional
if (circular)
{
return Alpaca.throwErrorWithCallback("Circular reference detected for schema: " + JSON.stringify(itemSchema), self.errorCallback);
}

var arrayValues = self.getValue();


//var itemData = Alpaca.createEmptyDataInstance(itemSchema);
var itemData = self.children[itemIndex].getValue();
// XXX no cloning necessary?
self.addItem(itemIndex + 1, itemSchema, itemOptions, itemData, function(item) {

// this is necessary because some underlying fields require their data to be reset
// in order for the display to work out properly (radio fields)
arrayValues.splice(itemIndex + 1, 0, item.getValue());
self.setValue(arrayValues);

if (callback) {
callback(item);
}
});
});
},

handleActionBarRemoveItemClick: function(itemIndex, callback)
{
var self = this;
Expand Down