2017-07-27 12:31:18 +02:00
|
|
|
// watches changes in the file upload control (input[file]) and
|
|
|
|
// puts the files selected in an attribute
|
2017-07-29 14:42:06 +02:00
|
|
|
var app = angular.module("webui.directives.fileselect", ["webui.services.deps"]);
|
|
|
|
app.directive("indeterminate", [
|
|
|
|
"$parse", function syncInput (parse) {
|
|
|
|
return {
|
|
|
|
require : "ngModel",
|
|
|
|
// Restrict the directive so it can only be used as an attribute
|
|
|
|
restrict : "A",
|
2017-07-27 12:31:18 +02:00
|
|
|
|
2017-07-29 14:42:06 +02:00
|
|
|
link : function link (scope, elem, attr, ngModelCtrl) {
|
|
|
|
// Whenever the bound value of the attribute changes we update
|
|
|
|
// use upward emit notification for change to prevent the performance penalty bring by $scope.$watch
|
|
|
|
var getter = parse(attr["ngModel"]);
|
|
|
|
var setter = getter.assign;
|
|
|
|
var children = []; // cache children input
|
|
|
|
var get = function () {
|
|
|
|
return getter(scope);
|
|
|
|
};
|
|
|
|
// the internal 'indeterminate' flag on the attached dom element
|
|
|
|
var setIndeterminateState = function (newValue) {
|
|
|
|
elem.prop("indeterminate", newValue);
|
|
|
|
};
|
|
|
|
var setModelValueWithoutSideEffect = function (newVal) {
|
|
|
|
setter(scope, newVal);
|
|
|
|
ngModelCtrl.$modelValue = newVal;
|
|
|
|
ngModelCtrl.$viewValue = newVal;
|
|
|
|
ngModelCtrl.$render();
|
|
|
|
};
|
|
|
|
var setWithSideEffect = function (newVal) {
|
|
|
|
ngModelCtrl.$setViewValue(newVal);
|
|
|
|
ngModelCtrl.$render();
|
|
|
|
};
|
|
|
|
var passIfLeafChild = function (callback) {
|
|
|
|
return function () {
|
|
|
|
if (children.length > 0) {
|
|
|
|
callback.apply(this, arguments);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var passIfNotIsLeafChild = function (callback) {
|
|
|
|
return function () {
|
|
|
|
if (children.length === 0) {
|
|
|
|
callback.apply(this, arguments);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var passThroughThisScope = function (callback) {
|
|
|
|
return function (event) {
|
|
|
|
if (event.targetScope !== event.currentScope) {
|
|
|
|
return callback.apply(this, arguments);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
if (attr["indeterminate"] && parse(attr["indeterminate"]).constant && !scope.$eval(attr["indeterminate"])) {
|
|
|
|
// is leaf input, Only receive parent change and emit child change event
|
|
|
|
setIndeterminateState(scope.$eval(attr["indeterminate"]));
|
|
|
|
ngModelCtrl.$viewChangeListeners.push(passIfNotIsLeafChild(function () {
|
|
|
|
scope.$emit("childSelectedChange");
|
|
|
|
}));
|
|
|
|
scope.$on("ParentSelectedChange", passThroughThisScope(
|
|
|
|
function (event, newVal) {
|
|
|
|
setWithSideEffect(newVal);
|
|
|
|
}));
|
|
|
|
scope.$emit("i'm child input", get);
|
|
|
|
setWithSideEffect(get());
|
|
|
|
scope.$emit("childSelectedChange");
|
|
|
|
} else {
|
|
|
|
// init first time and only once
|
|
|
|
// establish parent-child's relation
|
|
|
|
scope.$on("i'm child input", passThroughThisScope(
|
|
|
|
function (event, child) {
|
|
|
|
children.push(child);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
var updateBaseOnChildrenState = function () {
|
|
|
|
var allSelected = children.every(function (child) {
|
|
|
|
return child();
|
|
|
|
});
|
|
|
|
var anySeleted = children.some(function (child) {
|
|
|
|
return child();
|
|
|
|
});
|
|
|
|
setIndeterminateState(allSelected !== anySeleted);
|
|
|
|
setWithSideEffect(allSelected);
|
|
|
|
};
|
|
|
|
// is not leaf input, Only receive child change and parent change event
|
|
|
|
ngModelCtrl.$viewChangeListeners.push(passIfLeafChild(function () {
|
|
|
|
if (!elem.prop("indeterminate")) { // emit when prop indeterminate is set to false
|
|
|
|
scope.$broadcast("ParentSelectedChange", get());
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
// reset input state base on children inputs
|
|
|
|
scope.$on("childSelectedChange", passThroughThisScope(passIfLeafChild(updateBaseOnChildrenState)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
]);
|