/*
* Copyright (c) 2012-2019 Kaarle Ritvanen
* See LICENSE file for license details
*/
angular.module("aconf").directive("aconfFields", function() {
return {
restrict: "E",
scope: {node: "=", value: "=path"},
templateUrl: "directive/fields.html",
link: function(scope) {
scope.layout = scope.node && scope.node.meta.widget || "default";
}
}
}).directive("aconfInline", function() {
return {
restrict: "E",
scope: true,
transclude: true,
template: '
',
link: function(scope, element, attrs, ctrl, transclude) {
scope.$watch("node", function(node) {
if (node)
transclude(scope, function(clone) {
element.children().append(clone);
});
});
}
};
}).directive("aconfNode", function() {
return {
restrict: "C",
require: ["?aconfField", "?^^aconfNode", "^^aconfLayout"],
link: {
pre: function(scope, element, attrs, ctrl) {
var field = ctrl[0];
var parent = ctrl[1];
var layout = ctrl[2];
var fscope = field ? field.scope : scope;
if (parent) {
scope.level = parent.level + 1;
layout.query(fscope.value).then(function(node) {
scope.node = node;
fscope.node = node;
});
}
else scope.level = 1;
scope.$watch("node", function(node) {
if (!node) return;
scope.checkValidity = function(initial) {
var valid = node.validate();
fscope.invalid = !node.isNodeValid();
if (!(initial && valid)) layout.validationReady(valid);
};
scope.checkValidity(true);
});
}
},
controller: function($scope) {
Object.defineProperty(this, "level", {get: function() {
return $scope.level;
}});
Object.defineProperty(this, "data", {get: function() {
return $scope.node;
}});
this.updated = function(field) {
$scope.checkValidity();
$scope.$broadcast("updated", field);
};
}
};
}).directive("aconfHeader", function() {
return {
restrict: "E",
link: function(scope, element) {
element.html(
$("")
.text(scope.node.meta["ui-name"])
);
scope.$watch("invalid", function(invalid) {
if (invalid) element.addClass("invalid");
else element.removeClass("invalid");
});
}
};
}).directive("aconfCheckboxes", function() {
return {
restrict: "E",
scope: true,
templateUrl: "directive/checkboxes.html",
link: function(scope) {
scope.choices = _.filter(
scope.node.meta.members.choice,
function(ch) {
ch.checked = _.contains(scope.node.data, ch.value);
return ch.enabled || ch.checked;
}
);
}
};
}).directive("aconfSetCheckbox", function() {
return {
restrict: "E",
scope: {choice: "="},
templateUrl: "directive/set-checkbox.html",
link: {
pre: function(scope) {
scope.name = scope.choice.value;
scope.value = scope.choice.checked;
scope.set = true;
}
}
};
}).directive("aconfModel", function() {
return {
restrict: "E",
scope: true,
transclude: true,
template: '',
link: {
pre: function(scope, element, attrs, ctrl, transclude) {
scope.isRelevant = function(field) {
return scope.node.match(field.condition);
};
scope.$on("updated", function(event, updatedField) {
_.each(scope.fields, function(field, i, fields) {
if (field.name == updatedField ||
!scope.isRelevant(field))
return;
if (field.dynamic)
scope.node.metaRequest(field.name).success(
function(data) { fields[i] = data; }
);
if (field.dynamic ||
(field.condition &&
updatedField in field.condition))
fields[i] = _.clone(field);
});
});
transclude(scope, function(clone) {
element.children().append(clone);
});
}
}
};
}).directive("aconfModelFields", function() {
return {
restrict: "C",
require: "?aconfField",
link: function(scope, element, attrs, ctrl) {
if (ctrl) scope = ctrl.scope;
scope.$watch("node", function(node) {
if (!node) return;
scope.fields = _.where(node.meta.fields, {visible: true});
scope.columns = _.filter(scope.fields, function(field) {
return !(field.detail || field.condition);
});
scope.$emit("columns", _.pluck(scope.columns, "ui-name"));
scope.invoke = function(action) {
node.invoke(action).then(function() {
alert("Done");
}, function() { alert("Fail"); });
};
});
}
};
}).directive(
"aconfCollection", function($modal, $q, aconfErrorFormat, aconfType) {
return {
restrict: "E",
scope: true,
templateUrl: "directive/collection.html",
require: "^^aconfLayout",
link: function(scope, element, attrs, ctrl) {
var node = scope.node;
var meta = node.meta;
scope.$watch("node.data", function(data) {
if (!aconfType.isCollection(meta) ||
(scope.fields &&
_.keys(data).length == scope.fields.length))
return;
scope.fields = _.map(data, function(value, name) {
if (meta.type == "set") name = data[name];
else if (_.isArray(data)) name++;
var set = meta.type == "set";
return {
name: name,
label: set ? null : meta["ui-member"] + " " + name,
editable: meta.editable && !set,
removable: _.contains(meta.removable, name),
meta: meta.members
};
});
}, true);
if (!meta.editable) return;
var list = meta.type == "list";
var set = meta.type == "set";
function insert(name) {
return $q(function(resolve, reject) {
var task;
if (aconfType.isTreeNode(meta.members))
task = node.set(name, {});
else if (set) task = node.add(name);
if (task)
task.then(resolve, function(resp) {
node.delete(name);
reject(resp);
});
else node.set(name, null).catch(function(resp) {
resolve(false);
});
});
}
if (list) {
scope.$watch(
"!node.data.length || node.get(node.data.length, true) != null",
function(saved) {
scope.insert = saved && function() {
ctrl.updateRequest(insert(node.data.length + 1));
};
}
);
scope.sortable = {
start: function(event, ui) {
var index = ui.item.index();
if (!node.isSubtreeValid()) {
ui.item.sortable.cancel();
index = -1;
}
ui.item.data("index", index);
},
stop: function(event, ui) {
var oldIndex = ui.item.data("index") + 1;
var newIndex = ui.item.index() + 1;
if (oldIndex && newIndex != oldIndex)
ctrl.updateRequest(
node.move(oldIndex, newIndex)
);
}
};
return;
}
scope.insert = function() {
$modal.open({
backdrop: false,
templateUrl: "insert.html",
controller: function($scope, $modalInstance) {
$scope.submit = function() {
var name = $scope.value;
if (set ? _.contains(node.data, name) :
name in node.data) {
ctrl.validationReady(
"Already exists: " + name
);
return;
}
insert(name).then(function(txnValid) {
$modalInstance.close();
ctrl.validationReady(txnValid);
}, function(resp) {
$scope.error = aconfErrorFormat(resp);
});
};
$scope.close = function() {
$modalInstance.dismiss();
};
}
}).rendered.then(function($element) {
$(".modal-body input[type=text]").focus();
});
};
}
};
}
).directive("aconfTabularLayout", function() {
return {
restrict: "E",
scope: true,
templateUrl: "directive/tabular-layout.html",
link: {
pre: function(scope) {
scope.$on("columns", function(event, columns) {
scope.columns = columns;
});
}
}
};
});