summaryrefslogtreecommitdiffstats
path: root/web/field.js
diff options
context:
space:
mode:
Diffstat (limited to 'web/field.js')
-rw-r--r--web/field.js183
1 files changed, 183 insertions, 0 deletions
diff --git a/web/field.js b/web/field.js
new file mode 100644
index 0000000..deee541
--- /dev/null
+++ b/web/field.js
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2012-2015 Kaarle Ritvanen
+ * See LICENSE file for license details
+ */
+
+angular.module("aconf").directive("aconfWidget", function(aconfErrorFormat) {
+ return {
+ restrict: "E",
+ scope: {field: "=", formField: "="},
+ templateUrl: "directive/widget.html"
+ };
+}).directive("aconfField", function(aconfErrorFormat) {
+ return {
+ restrict: "A",
+ transclude: true,
+ scope: {field: "=aconfField"},
+ require: ["^^aconfLayout", "^^aconfNode"],
+ link: {
+ pre: function(scope, element, attrs, ctrl, transclude) {
+ var layout = ctrl[0];
+ var node = ctrl[1];
+
+ scope.name = scope.field.name;
+ scope.condition = scope.field.meta.condition;
+
+ var data = node.data;
+ scope.value = data.get(scope.name);
+ scope.status = function() { return data.status(scope.name); };
+ scope.delete = function() {
+ layout.updateRequest(data.delete(scope.name));
+ };
+
+ transclude(scope, function(clone) { element.append(clone); });
+ }
+ },
+ controller: function($scope) {
+ Object.defineProperty(this, "scope", {get: function() {
+ return $scope;
+ }});
+ this.setError = function(resp) {
+ $scope.error = resp ? aconfErrorFormat(resp) : null;
+ };
+ }
+ };
+}).directive("aconfSync", function($q, aconfErrorFormat, aconfExclusive) {
+ return {
+ restrict: "C",
+ require: ["^^aconfField", "^^aconfLayout", "^^aconfNode", "ngModel"],
+ link: function(scope, element, attrs, ctrl) {
+ var field = ctrl[0];
+ var layout = ctrl[1];
+ var node = ctrl[2];
+ var model = ctrl[3];
+
+ var data = node.data;
+
+ function getStatus() { return data.status(scope.name); }
+
+ switch (getStatus()) {
+ case "invalid":
+ model.$setValidity("aconf", false);
+ break;
+ case "changed":
+ model.$setDirty();
+ }
+
+ var initial = true;
+ model.$asyncValidators.aconf = function(modelValue, viewValue) {
+ if (aconfExclusive.isRunning) return $q.when();
+
+ var value = modelValue || viewValue;
+ if (value === "") value = null;
+ else if (value instanceof Date)
+ value = value.toISOString().substring(0, 10);
+
+ var def;
+
+ if (initial && getStatus() != "invalid" && !scope.condition)
+ def = $q.when(null);
+
+ else if (scope.set)
+ def = value ? data.add(scope.name) :
+ data.delete(scope.name);
+
+ else def = data.set(scope.name, value);
+
+ initial = false;
+
+ def.then(function(txnValid) {
+ field.setError();
+ if (!data.status(scope.name)) model.$setPristine();
+ if (txnValid != null) {
+ layout.validationReady(txnValid);
+ node.updated(scope.name);
+ }
+
+ }, function(resp) {
+ field.setError(resp);
+ layout.validationReady(false);
+ });
+
+ return def;
+ }
+ }
+ };
+}).directive("aconfBasicInput", function() {
+ return {
+ restrict: "E",
+ transclude: true,
+ templateUrl: "directive/basic-input.html"
+ };
+}).directive("aconfDelButton", function() {
+ return {
+ restrict: "E",
+ scope: {},
+ templateUrl: "directive/del-button.html",
+ require: "?^^aconfField",
+ link: function(scope, element, attrs, ctrl) {
+ if (ctrl && ctrl.scope.field.removable) scope.delete = ctrl.scope.delete;
+ }
+ };
+}).directive("aconfError", function() {
+ return {restrict: "E", templateUrl: "directive/error.html"};
+
+}).directive("aconfInput", function() {
+ return {
+ restrict: "E", transclude: true, templateUrl: "directive/input.html"
+ };
+
+}).directive("aconfAudio", function() {
+ return {
+ restrict: "E",
+ scope: true,
+ templateUrl: "directive/audio.html",
+ require: "^^aconfLayout",
+ link: function(scope, element, attrs, ctrl) {
+ scope.play = function() {
+ ctrl.query(scope.value).then(function(data) {
+ element.html($("<audio>").attr({
+ src: data.data, autoplay: true, controls: true
+ }));
+ });
+ };
+ }
+ };
+}).directive("aconfDate", function() {
+ return {
+ restrict: "E",
+ scope: true,
+ templateUrl: "directive/date.html",
+ link: {
+ pre: function(scope) {
+ scope.value = new Date(scope.value);
+ scope.opened = false;
+ scope.open = function(event) {
+ event.preventDefault();
+ event.stopPropagation();
+ scope.opened = true;
+ }
+ }
+ }
+ };
+}).directive("aconfLink", function() {
+ return {
+ restrict: "E",
+ scope: {label: "@", path: "=", status: "="},
+ templateUrl: "directive/link.html"
+ };
+}).directive("aconfSelect", function() {
+ return {
+ restrict: "E",
+ templateUrl: "directive/select.html",
+ link: {
+ pre: function(scope, element) {
+ scope.choices = _.filter(scope.field.meta.choice, function(ch) {
+ return ch.enabled || ch.value == scope.value;
+ });
+ if (!scope.field.meta.required || !scope.value)
+ scope.choices.unshift({value: null, "ui-value": "(none)"});
+ }
+ }
+ };
+});