remove some es5 feature, decrease recheck times

This commit is contained in:
vitam 2017-07-29 20:15:01 +02:00
parent 942dbe6f3f
commit 83ba82d4bc
2 changed files with 49 additions and 22 deletions

View File

@ -23,7 +23,7 @@
<script src="js/libs/jquery-2.2.4.min.js"></script> <script src="js/libs/jquery-2.2.4.min.js"></script>
<script src="js/libs/lodash-4.17.3.min.js"></script> <script src="js/libs/lodash-4.17.3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.js"></script> <script src="js/libs/angular.min.js"></script>
<script src="js/libs/angularui-bootstrap-tpls.min.js"></script> <script src="js/libs/angularui-bootstrap-tpls.min.js"></script>
<script src="js/libs/bootstrap-filestyle.js"></script> <script src="js/libs/bootstrap-filestyle.js"></script>

View File

@ -12,8 +12,10 @@ app.directive("indeterminate", [
// Whenever the bound value of the attribute changes we update // 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 // use upward emit notification for change to prevent the performance penalty bring by $scope.$watch
var getter = parse(attr["ngModel"]); var getter = parse(attr["ngModel"]);
var setter = getter.assign; // var setter = getter.assign;
var children = []; // cache children input var children = []; // cache children input
var cacheSelectedSubInputNumber = 0;
var cacheNoSelectedSubInputNumber = 0;
var get = function () { var get = function () {
return getter(scope); return getter(scope);
}; };
@ -21,18 +23,18 @@ app.directive("indeterminate", [
var setIndeterminateState = function (newValue) { var setIndeterminateState = function (newValue) {
elem.prop("indeterminate", newValue); elem.prop("indeterminate", newValue);
}; };
var setWithSideEffect = function (newVal) { var setModelValueWithSideEffect = function (newVal) { // will cause to emit corresponding events
ngModelCtrl.$setViewValue(newVal); ngModelCtrl.$setViewValue(newVal);
ngModelCtrl.$render(); ngModelCtrl.$render();
}; };
var passIfLeafChild = function (callback) { // ensure to execute callback when this input have one or more subinputs var passIfIsLeafChild = function (callback) { // ensure to execute callback only when this input has one or more subinputs
return function () { return function () {
if (children.length > 0) { if (children.length > 0) {
callback.apply(this, arguments); callback.apply(this, arguments);
} }
}; };
}; };
var passIfNotIsLeafChild = function (callback) { // ensure to execute callback when this input havent subinput var passIfNotIsLeafChild = function (callback) { // ensure to execute callback only when this input hasn't subinput
return function () { return function () {
if (children.length === 0) { if (children.length === 0) {
callback.apply(this, arguments); callback.apply(this, arguments);
@ -46,19 +48,27 @@ app.directive("indeterminate", [
} }
}; };
}; };
var catchEventOnlyOnce = function (callback) { // only fire once, and stop event's propagation
return function (event) {
callback.apply(this, arguments);
return event.stopPropagation();
};
};
if (attr["indeterminate"] && parse(attr["indeterminate"]).constant) {
setIndeterminateState(scope.$eval(attr["indeterminate"])); // set to default value (set in template)
}
if (attr["indeterminate"] && parse(attr["indeterminate"]).constant && !scope.$eval(attr["indeterminate"])) { if (attr["indeterminate"] && parse(attr["indeterminate"]).constant && !scope.$eval(attr["indeterminate"])) {
// is leaf input, Only receive parent change and emit child change event // when this input wont have subinput, they will only receive parent change and emit child change event
setIndeterminateState(scope.$eval(attr["indeterminate"]));
ngModelCtrl.$viewChangeListeners.push(passIfNotIsLeafChild(function () { ngModelCtrl.$viewChangeListeners.push(passIfNotIsLeafChild(function () {
scope.$emit("childSelectedChange"); scope.$emit("childSelectedChange", get());
})); }));
scope.$on("ParentSelectedChange", passThroughThisScope( scope.$on("ParentSelectedChange", passThroughThisScope(passIfNotIsLeafChild(
function (event, newVal) { function (event, newVal) {
setWithSideEffect(newVal); // set value to parent's value; this will cause listener to emit childChange event; this won't be a infinite loop setModelValueWithSideEffect(newVal); // set value to parent's value; this will cause listener to emit childChange event; this won't be a infinite loop
})); })));
// init first time and only once // init first time and only once
scope.$emit("i'm child input", get); scope.$emit("i'm child input", get);
scope.$emit("childSelectedChange"); // force emitted, and force the parent change their state base on children at first time scope.$emit("childSelectedChange", get()); // force emitted, and force the parent change their state base on children at first time
} else { } else {
// establish parent-child's relation // establish parent-child's relation
// listen for the child emitted token // listen for the child emitted token
@ -67,25 +77,42 @@ app.directive("indeterminate", [
children.push(child); children.push(child);
}) })
); );
var updateBaseOnChildrenState = function () { var updateBaseOnChildrenState = function (event, newChildValue) {
var allSelected = children.every(function (child) { if ((cacheSelectedSubInputNumber + cacheNoSelectedSubInputNumber) !== children.length) {
return child(); cacheSelectedSubInputNumber = 0;
}); cacheNoSelectedSubInputNumber = 0;
var anySeleted = children.some(function (child) { for (var i = 0; i < children.length; i++) {
return child(); if (children[i]()) {
}); cacheSelectedSubInputNumber += 1;
} else {
cacheNoSelectedSubInputNumber += 1;
}
}
} else {
// no need for recalculated children state
// just make a few change to cache value
if (newChildValue) {
cacheSelectedSubInputNumber++;
cacheNoSelectedSubInputNumber--;
} else {
cacheSelectedSubInputNumber--;
cacheNoSelectedSubInputNumber++;
}
}
var allSelected = (cacheNoSelectedSubInputNumber === 0);
var anySeleted = (cacheSelectedSubInputNumber > 0);
setIndeterminateState(allSelected !== anySeleted); // if at least one is selected, but not all then set input property indeterminate to true setIndeterminateState(allSelected !== anySeleted); // if at least one is selected, but not all then set input property indeterminate to true
setWithSideEffect(allSelected); setModelValueWithSideEffect(allSelected);
}; };
// is not leaf input, Only receive child change and parent change event // is not leaf input, Only receive child change and parent change event
ngModelCtrl.$viewChangeListeners.push(passIfLeafChild(function () { ngModelCtrl.$viewChangeListeners.push(passIfIsLeafChild(function () {
// emit when property indeterminate is set to false, prevent recursively emitting event from parent to children, children to parent // emit when property indeterminate is set to false, prevent recursively emitting event from parent to children, children to parent
if (!elem.prop("indeterminate")) { if (!elem.prop("indeterminate")) {
scope.$broadcast("ParentSelectedChange", get()); scope.$broadcast("ParentSelectedChange", get());
} }
})); }));
// reset input state base on children inputs // reset input state base on children inputs
scope.$on("childSelectedChange", passThroughThisScope(passIfLeafChild(updateBaseOnChildrenState))); scope.$on("childSelectedChange", passThroughThisScope(passIfIsLeafChild(updateBaseOnChildrenState)));
} }
} }
}; };