diff options
Diffstat (limited to 'web/field.js')
-rw-r--r-- | web/field.js | 183 |
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)"}); + } + } + }; +}); |