<commit_before>define(function(require) {
  'use strict';

  var modules = require('modules');
  var _ = require('lodash');
  var angular = require('angular');

  require('scripts/common/services/properties_services');

  var ComplexPropertyModalCtrl = ['$scope', '$modalInstance', 'formDescriptorServices',
    function($scope, $modalInstance, formDescriptorServices) {
      $scope.configuration = {
        dependencies: $scope.dependencies
      };
      var descriptorQuery = {
        propertyDefinition: $scope.definition,
        dependencies: $scope.dependencies
      };
      //descriptor of the config
      formDescriptorServices.getToscaComplexTypeDescriptor({}, angular.toJson(descriptorQuery), function(result) {
        $scope.formDescription = result.data;
      });

      $scope.save = function(value) {
        $scope.propertySave(value);
      };

      $scope.remove = function() {
        $scope.propertySave(undefined);
        $modalInstance.dismiss(undefined);
      };

      $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
      };
    }
  ];

  var PropertySuggestionModalCtrl = ['$scope', '$modalInstance',
    function($scope, $modalInstance) {
      $scope.result = '';

      $scope.create = function(result) {
        $modalInstance.close(result);
      };

      $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
      };
    }
  ];

  modules.get('a4c-common', ['pascalprecht.translate']).controller('PropertiesCtrl', ['$scope', 'propertiesServices', '$translate', '$modal', '$timeout', 'propertySuggestionServices',
    function($scope, propertiesServices, $translate, $modal, $timeout, propertySuggestionServices) {
      if (_.undefined($scope.translated)) {
        $scope.translated = false;
      }

      $scope.showLongTextChoice = false;

      $scope.switchLongTextChoice = function(on) {
        $scope.showLongTextChoice = on;
      };

      $scope.switchToLongText = function($event) {
        $scope.isLongText = !$scope.isLongText;
        $timeout(function() {
          angular.element($event.target).prev().trigger('click');
        });
      };

      $scope.suggestion = {
        get: function(text) {
          if (_.defined($scope.definition.suggestionId)) {
            return propertySuggestionServices.get({
              input: text,
              limit: 5,
              suggestionId: $scope.definition.suggestionId
            }).$promise.then(function(result) {
              if (_.defined(result.data)) {
                if (result.data.indexOf(text) < 0) {
                  result.data.push(text);
                }
                return result.data;
              } else {
                return [];
              }
            });
          } else {
            return [];
          }
        },
        waitBeforeRequest: 0,
        minLength: 1
      };

      /* method private to factorise all call to the serve and trigge errors */
      var callSaveService = function(propertyRequest) {
        var saveResult = $scope.onSave(propertyRequest);

        // If the callback return a promise
        if (_.defined(saveResult) && _.defined(saveResult.then)) {
          return saveResult.then(function(saveResult) {
            if (_.defined(saveResult.error)) {
              // Constraint error display + translation
              var constraintInfo = saveResult.data;
              // Error message handled by x-editable
              if (saveResult.error.code === 800) {
                return $translate.instant('ERRORS.' + saveResult.error.code + '.' + constraintInfo.name, constraintInfo);
              } else {
                return $translate.instant('ERRORS.' + saveResult.error.code, constraintInfo);
              }
            }
          });
        }
      };

      $scope.propertySave = function(data, unit) {
        delete $scope.unitError;
        if (_.isBoolean(data)) {
          data = data.toString();
        } else if (_.isEmpty(data)) {
          data = null;
        }

        if (!_.isEmpty(data) && _.defined($scope.definitionObject.units)) {
          if (_.undefined(unit)) {
            unit = $scope.definitionObject.uiUnit;
          }
          data += ' ' + unit;
        }
        // check constraint here
        var propertyRequest = {
          propertyName: $scope.propertyName,
          propertyDefinition: $scope.definition,
          propertyValue: data
        };

        if (_.defined($scope.definition.suggestionId) && _.defined(data) && data !== null) {
          return propertySuggestionServices.get({
            input: data,
            limit: 5,
            suggestionId: $scope.definition.suggestionId
          }).$promise.then(function(suggestionResult) {
            var promise;
            $scope.propertySuggestionData = {
              suggestions: suggestionResult.data,
              propertyValue: data
            };
            if (suggestionResult.data.indexOf(data) < 0) {
              var modalInstance = $modal.open({
                templateUrl: 'propertySuggestionModal.html',
                controller: PropertySuggestionModalCtrl,
                scope: $scope
              });
              promise = modalInstance.result.then(function(modalResult) {
                if (suggestionResult.data.indexOf(modalResult) < 0) {
                  propertySuggestionServices.add([], {
                    suggestionId: $scope.definition.suggestionId,
                    value: modalResult
                  }, null);
                }
                propertyRequest.propertyValue = modalResult;
                return callSaveService(propertyRequest);
              }, function() {
                return $translate.instant('CANCELLED');
              });
            } else {
              promise = callSaveService(propertyRequest);
            }
            return promise;
          });
        } else {
          return callSaveService(propertyRequest);
        }
      };

      $scope.saveUnit = function(unit) {
        $scope.definitionObject.uiUnit = unit;
        if (_.defined($scope.definitionObject.uiValue)) {
          var savePromise = $scope.propertySave($scope.definitionObject.uiValue, unit);
          if (_.defined(savePromise)) {
            savePromise.then(function(error) {
              if (_.defined(error)) {
                $scope.unitError = error;
              }
            });
          }
        }
      };

      $scope.saveReset = function(resetValue) {
        var resetUnit = null;
        if (_.defined($scope.definitionObject.units) && !_.undefined(resetValue)) {
          // reset value de la forme : "VALUE UNIT" > split by space
          var splitedValueUnit = resetValue.split(' ');
          resetValue = splitedValueUnit[0];
          resetUnit = splitedValueUnit[1];
        }
        var savePromise = $scope.propertySave(resetValue, resetUnit);
        if (_.defined(savePromise)) {
          savePromise.then(function(error) {
            if (_.defined(error)) {
              $scope.unitError = error;
            }
          });
        }
      };

      // specific wrapper for boolean type to handle "css checkbox"
      $scope.propertySaveBoolean = function(propertyValue) {
        $scope.propertySave(propertyValue);
        $scope.definitionObject.uiValue = propertyValue;
      };

      /**
       * Return the property constraint identifier to represent it in the UI
       * We can define the représentation regardint the property "type" or "constraint"
       * Managed identifier / constraint :
       *  - validValues => select
       *  - date => date picker (standby)
       *  - boolean => checkbox
       *  - string => input text / password handled
       *  - inRange => slider
       */
      $scope.definitionObject = {};

      $scope.init = function() {
        $scope.$watch('propertyValue', function() {
          $scope.initScope();
        }, true);

        $scope.$watch('definition', function() {
          $scope.initScope();
        }, true);
        $scope.initScope();
      };

      $scope.initScope = function() {
        // Define properties
        if (!_.defined($scope.definition)) {
          return;
        }

        // Now a property is an AbstractPropertyValue : (Scalar or Function)
        var shownValue = $scope.propertyValue;
        if (_.defined($scope.propertyValue) && $scope.propertyValue.definition === false) {
          if ($scope.propertyValue.hasOwnProperty('value')) {
            // Here handle scalar value
            shownValue = $scope.propertyValue.value;
          } else if ($scope.propertyValue.hasOwnProperty('function') && $scope.propertyValue.hasOwnProperty('parameters') && $scope.propertyValue.parameters.length > 0) {
            shownValue = $scope.propertyValue.function + ': ' + _($scope.propertyValue.parameters).toString();
            //should not edit a function
            $scope.editable = false;
          }
        }

        // handling default value
        shownValue = shownValue || $scope.definition.default;
        $scope.definitionObject.hasDefaultValue = _.defined($scope.definition.default);

        // merge the constraints from the definition and from the type
        var constraints = [];
        if (_.defined($scope.definition.constraints)) {
          constraints.push($scope.definition.constraints);
        }
        if (_.defined($scope.propertyType) && _.defined($scope.propertyType.constraints)) {
          constraints.push($scope.propertyType.constraints);
        }

        // Second phase : regarding constraints
        for (var i = 0; i < constraints.length; i++) {
          if (constraints[i].hasOwnProperty('validValues')) {
            $scope.definitionObject.uiName = 'select';
            $scope.definitionObject.uiValue = shownValue;
            $scope.definitionObject.uiSelectValues = constraints[i].validValues;
            return $scope.definitionObject;
          }
          if (constraints[i].hasOwnProperty('inRange')) {
            $scope.definitionObject.uiName = 'range';
            $scope.definitionObject.uiValue = shownValue;
            $scope.definitionObject.uiValueMax = constraints[i].rangeMaxValue;
            $scope.definitionObject.uiValueMin = constraints[i].rangeMinValue;
            return $scope.definitionObject;
          }
        }

        var splitScalarUnitValue = function(upperCase) {
          if (_.defined(shownValue)) {
            var shownValueTokens = shownValue.split(/\s+/);
            $scope.definitionObject.uiValue = shownValueTokens[0];
            if (upperCase) {
              $scope.definitionObject.uiUnit = shownValueTokens[1].toUpperCase();
            } else {
              $scope.definitionObject.uiUnit = shownValueTokens[1].toLowerCase();
            }
          } else {
            $scope.definitionObject.uiUnit = $scope.definitionObject.units[0];
            $scope.definitionObject.uiValue = shownValue;
          }
        };
        $scope.splitScalarUnitValue = splitScalarUnitValue;

        var type = $scope.definition.type;
        if (_.defined($scope.propertyType) && $scope.propertyType.deriveFromSimpleType) {
          type = $scope.propertyType.derivedFrom[0];
        }

        // Second phase : regardless constraints
        switch (type) {
          case 'boolean':
            $scope.definitionObject.uiName = 'checkbox';
            if (_.undefined(shownValue)) {
              $scope.definitionObject.uiValue = false;
            } else if (typeof shownValue === 'boolean') {
              $scope.definitionObject.uiValue = shownValue;
            } else {
              $scope.definitionObject.uiValue = (shownValue === 'true');
            }
            break;
          case 'timestamp':
            $scope.definitionObject.uiName = 'date';
            $scope.definitionObject.uiValue = shownValue;
            break;
          case 'scalar-unit.size':
            $scope.definitionObject.uiName = 'scalar-unit';
            $scope.definitionObject.units = ['B', 'KB', 'KIB', 'MB', 'MIB', 'GB', 'GIB', 'TB', 'TIB'];
            splitScalarUnitValue(true);
            break;
          case 'scalar-unit.time':
            $scope.definitionObject.uiName = 'scalar-unit';
            $scope.definitionObject.units = ['d', 'h', 'm', 's', 'ms', 'us', 'ns'];
            splitScalarUnitValue(false);
            break;
          case 'scalar-unit.frequency':
            $scope.definitionObject.uiName = 'scalar-unit';
            $scope.definitionObject.units = ['Hz', 'KHz', 'MHz', 'GHz'];
            splitScalarUnitValue(true);
            break;
          case 'version':
          case 'float':
          case 'integer':
          case 'string':
            $scope.definitionObject.uiName = 'string';
            $scope.definitionObject.uiValue = shownValue;
            $scope.definitionObject.uiPassword = $scope.definition.password;
            $scope.isLongText = _.defined(shownValue) && typeof shownValue === 'string' && shownValue.indexOf('\n') > -1;
            break;
          default :
            $scope.definitionObject.uiName = 'complex';
            $scope.definitionObject.uiValue = shownValue;
            break;
        }
        // Phase one valid or not ?
        if (!_.isEmpty($scope.definitionObject)) {
          return $scope.definitionObject;
        }
      };

      $scope.openComplexPropertyModal = function() {
        $modal.open({
          templateUrl: 'views/common/property_display_complex_modal.html',
          controller: ComplexPropertyModalCtrl,
          windowClass: 'searchModal',
          scope: $scope
        });
      };

      /** Reset the property to the default value if any */
      $scope.resetProperty = function resetPropertyToDefault() {
        $scope.initScope();
        $scope.saveReset($scope.definition.default.value);
        if ($scope.propertyValue.hasOwnProperty('value')) {
          $scope.propertyValue.value = $scope.definition.default.value; // if same value affected, no watch applied
        } else {
          $scope.propertyValue = $scope.definition.default;
        }
      };

      // Init managed property
      $scope.init();
    }
  ]); // controller
}); // define
<commit_msg>Fix a bug when a primitive field (string, version, etc.) have default value.<commit_after>define(function(require) {
  'use strict';

  var modules = require('modules');
  var _ = require('lodash');
  var angular = require('angular');

  require('scripts/common/services/properties_services');

  var ComplexPropertyModalCtrl = ['$scope', '$modalInstance', 'formDescriptorServices',
    function($scope, $modalInstance, formDescriptorServices) {
      $scope.configuration = {
        dependencies: $scope.dependencies
      };
      var descriptorQuery = {
        propertyDefinition: $scope.definition,
        dependencies: $scope.dependencies
      };
      //descriptor of the config
      formDescriptorServices.getToscaComplexTypeDescriptor({}, angular.toJson(descriptorQuery), function(result) {
        $scope.formDescription = result.data;
      });

      $scope.save = function(value) {
        $scope.propertySave(value);
      };

      $scope.remove = function() {
        $scope.propertySave(undefined);
        $modalInstance.dismiss(undefined);
      };

      $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
      };
    }
  ];

  var PropertySuggestionModalCtrl = ['$scope', '$modalInstance',
    function($scope, $modalInstance) {
      $scope.result = '';

      $scope.create = function(result) {
        $modalInstance.close(result);
      };

      $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
      };
    }
  ];

  modules.get('a4c-common', ['pascalprecht.translate']).controller('PropertiesCtrl', ['$scope', 'propertiesServices', '$translate', '$modal', '$timeout', 'propertySuggestionServices',
    function($scope, propertiesServices, $translate, $modal, $timeout, propertySuggestionServices) {
      if (_.undefined($scope.translated)) {
        $scope.translated = false;
      }

      $scope.showLongTextChoice = false;

      $scope.switchLongTextChoice = function(on) {
        $scope.showLongTextChoice = on;
      };

      $scope.switchToLongText = function($event) {
        $scope.isLongText = !$scope.isLongText;
        $timeout(function() {
          angular.element($event.target).prev().trigger('click');
        });
      };

      $scope.suggestion = {
        get: function(text) {
          if (_.defined($scope.definition.suggestionId)) {
            return propertySuggestionServices.get({
              input: text,
              limit: 5,
              suggestionId: $scope.definition.suggestionId
            }).$promise.then(function(result) {
              if (_.defined(result.data)) {
                if (result.data.indexOf(text) < 0) {
                  result.data.push(text);
                }
                return result.data;
              } else {
                return [];
              }
            });
          } else {
            return [];
          }
        },
        waitBeforeRequest: 0,
        minLength: 1
      };

      /* method private to factorise all call to the serve and trigge errors */
      var callSaveService = function(propertyRequest) {
        var saveResult = $scope.onSave(propertyRequest);

        // If the callback return a promise
        if (_.defined(saveResult) && _.defined(saveResult.then)) {
          return saveResult.then(function(saveResult) {
            if (_.defined(saveResult.error)) {
              // Constraint error display + translation
              var constraintInfo = saveResult.data;
              // Error message handled by x-editable
              if (saveResult.error.code === 800) {
                return $translate.instant('ERRORS.' + saveResult.error.code + '.' + constraintInfo.name, constraintInfo);
              } else {
                return $translate.instant('ERRORS.' + saveResult.error.code, constraintInfo);
              }
            }
          });
        }
      };

      $scope.propertySave = function(data, unit) {
        delete $scope.unitError;
        if (_.isBoolean(data)) {
          data = data.toString();
        } else if (_.isEmpty(data)) {
          data = null;
        }

        if (!_.isEmpty(data) && _.defined($scope.definitionObject.units)) {
          if (_.undefined(unit)) {
            unit = $scope.definitionObject.uiUnit;
          }
          data += ' ' + unit;
        }
        // check constraint here
        var propertyRequest = {
          propertyName: $scope.propertyName,
          propertyDefinition: $scope.definition,
          propertyValue: data
        };

        if (_.defined($scope.definition.suggestionId) && _.defined(data) && data !== null) {
          return propertySuggestionServices.get({
            input: data,
            limit: 5,
            suggestionId: $scope.definition.suggestionId
          }).$promise.then(function(suggestionResult) {
            var promise;
            $scope.propertySuggestionData = {
              suggestions: suggestionResult.data,
              propertyValue: data
            };
            if (suggestionResult.data.indexOf(data) < 0) {
              var modalInstance = $modal.open({
                templateUrl: 'propertySuggestionModal.html',
                controller: PropertySuggestionModalCtrl,
                scope: $scope
              });
              promise = modalInstance.result.then(function(modalResult) {
                if (suggestionResult.data.indexOf(modalResult) < 0) {
                  propertySuggestionServices.add([], {
                    suggestionId: $scope.definition.suggestionId,
                    value: modalResult
                  }, null);
                }
                propertyRequest.propertyValue = modalResult;
                return callSaveService(propertyRequest);
              }, function() {
                return $translate.instant('CANCELLED');
              });
            } else {
              promise = callSaveService(propertyRequest);
            }
            return promise;
          });
        } else {
          return callSaveService(propertyRequest);
        }
      };

      $scope.saveUnit = function(unit) {
        $scope.definitionObject.uiUnit = unit;
        if (_.defined($scope.definitionObject.uiValue)) {
          var savePromise = $scope.propertySave($scope.definitionObject.uiValue, unit);
          if (_.defined(savePromise)) {
            savePromise.then(function(error) {
              if (_.defined(error)) {
                $scope.unitError = error;
              }
            });
          }
        }
      };

      $scope.saveReset = function(resetValue) {
        var resetUnit = null;
        if (_.defined($scope.definitionObject.units) && !_.undefined(resetValue)) {
          // reset value de la forme : "VALUE UNIT" > split by space
          var splitedValueUnit = resetValue.split(' ');
          resetValue = splitedValueUnit[0];
          resetUnit = splitedValueUnit[1];
        }
        var savePromise = $scope.propertySave(resetValue, resetUnit);
        if (_.defined(savePromise)) {
          savePromise.then(function(error) {
            if (_.defined(error)) {
              $scope.unitError = error;
            }
          });
        }
      };

      // specific wrapper for boolean type to handle "css checkbox"
      $scope.propertySaveBoolean = function(propertyValue) {
        $scope.propertySave(propertyValue);
        $scope.definitionObject.uiValue = propertyValue;
      };

      /**
       * Return the property constraint identifier to represent it in the UI
       * We can define the représentation regardint the property "type" or "constraint"
       * Managed identifier / constraint :
       *  - validValues => select
       *  - date => date picker (standby)
       *  - boolean => checkbox
       *  - string => input text / password handled
       *  - inRange => slider
       */
      $scope.definitionObject = {};

      $scope.init = function() {
        $scope.$watch('propertyValue', function() {
          $scope.initScope();
        }, true);

        $scope.$watch('definition', function() {
          $scope.initScope();
        }, true);
        $scope.initScope();
      };

      $scope.initScope = function() {
        // Define properties
        if (!_.defined($scope.definition)) {
          return;
        }

        // Now a property is an AbstractPropertyValue : (Scalar or Function)
        var shownValue = $scope.propertyValue;
        if (_.defined($scope.propertyValue) && $scope.propertyValue.definition === false) {
          if ($scope.propertyValue.hasOwnProperty('value')) {
            // Here handle scalar value
            shownValue = $scope.propertyValue.value;
          } else if ($scope.propertyValue.hasOwnProperty('function') && $scope.propertyValue.hasOwnProperty('parameters') && $scope.propertyValue.parameters.length > 0) {
            shownValue = $scope.propertyValue.function + ': ' + _($scope.propertyValue.parameters).toString();
            //should not edit a function
            $scope.editable = false;
          }
        }

        // handling default value
        shownValue = shownValue || $scope.definition.default;
        $scope.definitionObject.hasDefaultValue = _.defined($scope.definition.default);

        // merge the constraints from the definition and from the type
        var constraints = [];
        if (_.defined($scope.definition.constraints)) {
          constraints.push($scope.definition.constraints);
        }
        if (_.defined($scope.propertyType) && _.defined($scope.propertyType.constraints)) {
          constraints.push($scope.propertyType.constraints);
        }

        // Second phase : regarding constraints
        for (var i = 0; i < constraints.length; i++) {
          if (constraints[i].hasOwnProperty('validValues')) {
            $scope.definitionObject.uiName = 'select';
            $scope.definitionObject.uiValue = shownValue;
            $scope.definitionObject.uiSelectValues = constraints[i].validValues;
            return $scope.definitionObject;
          }
          if (constraints[i].hasOwnProperty('inRange')) {
            $scope.definitionObject.uiName = 'range';
            $scope.definitionObject.uiValue = shownValue;
            $scope.definitionObject.uiValueMax = constraints[i].rangeMaxValue;
            $scope.definitionObject.uiValueMin = constraints[i].rangeMinValue;
            return $scope.definitionObject;
          }
        }

        var splitScalarUnitValue = function(upperCase) {
          if (_.defined(shownValue)) {
            var shownValueTokens = shownValue.split(/\s+/);
            $scope.definitionObject.uiValue = shownValueTokens[0];
            if (upperCase) {
              $scope.definitionObject.uiUnit = shownValueTokens[1].toUpperCase();
            } else {
              $scope.definitionObject.uiUnit = shownValueTokens[1].toLowerCase();
            }
          } else {
            $scope.definitionObject.uiUnit = $scope.definitionObject.units[0];
            $scope.definitionObject.uiValue = shownValue;
          }
        };
        $scope.splitScalarUnitValue = splitScalarUnitValue;

        var type = $scope.definition.type;
        if (_.defined($scope.propertyType) && $scope.propertyType.deriveFromSimpleType) {
          type = $scope.propertyType.derivedFrom[0];
        }

        // Second phase : regardless constraints
        switch (type) {
          case 'boolean':
            $scope.definitionObject.uiName = 'checkbox';
            if (_.undefined(shownValue)) {
              $scope.definitionObject.uiValue = false;
            } else if (typeof shownValue === 'boolean') {
              $scope.definitionObject.uiValue = shownValue;
            } else {
              $scope.definitionObject.uiValue = (shownValue === 'true');
            }
            break;
          case 'timestamp':
            $scope.definitionObject.uiName = 'date';
            $scope.definitionObject.uiValue = shownValue;
            break;
          case 'scalar-unit.size':
            $scope.definitionObject.uiName = 'scalar-unit';
            $scope.definitionObject.units = ['B', 'KB', 'KIB', 'MB', 'MIB', 'GB', 'GIB', 'TB', 'TIB'];
            splitScalarUnitValue(true);
            break;
          case 'scalar-unit.time':
            $scope.definitionObject.uiName = 'scalar-unit';
            $scope.definitionObject.units = ['d', 'h', 'm', 's', 'ms', 'us', 'ns'];
            splitScalarUnitValue(false);
            break;
          case 'scalar-unit.frequency':
            $scope.definitionObject.uiName = 'scalar-unit';
            $scope.definitionObject.units = ['Hz', 'KHz', 'MHz', 'GHz'];
            splitScalarUnitValue(true);
            break;
          case 'version':
          case 'float':
          case 'integer':
          case 'string':
            $scope.definitionObject.uiName = 'string';
            if(_.defined(shownValue.value)) {
              $scope.definitionObject.uiValue = shownValue.value;
            } else {
              $scope.definitionObject.uiValue = shownValue;
            }
            $scope.definitionObject.uiPassword = $scope.definition.password;
            $scope.isLongText = _.defined(shownValue) && typeof shownValue === 'string' && shownValue.indexOf('\n') > -1;
            break;
          default :
            $scope.definitionObject.uiName = 'complex';
            $scope.definitionObject.uiValue = shownValue;
            break;
        }
        // Phase one valid or not ?
        if (!_.isEmpty($scope.definitionObject)) {
          return $scope.definitionObject;
        }
      };

      $scope.openComplexPropertyModal = function() {
        $modal.open({
          templateUrl: 'views/common/property_display_complex_modal.html',
          controller: ComplexPropertyModalCtrl,
          windowClass: 'searchModal',
          scope: $scope
        });
      };

      /** Reset the property to the default value if any */
      $scope.resetProperty = function resetPropertyToDefault() {
        $scope.initScope();
        $scope.saveReset($scope.definition.default.value);
        if ($scope.propertyValue.hasOwnProperty('value')) {
          $scope.propertyValue.value = $scope.definition.default.value; // if same value affected, no watch applied
        } else {
          $scope.propertyValue = $scope.definition.default;
        }
      };

      // Init managed property
      $scope.init();
    }
  ]); // controller
}); // define
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var App = require('app');
require('controllers/main/admin/highAvailability/progress_controller');

App.HighAvailabilityRollbackController = App.HighAvailabilityProgressPageController.extend({

  name: "highAvailabilityRollbackController",

  failedTask: null,
  configsSaved: false,
  deletedHdfsClients: 0,
  numOfDelOperations: 0,

  content: Em.Object.create({
    masterComponentHosts: null
  }),

  commands: [
    'stopAllServices',
    'restoreHBaseConfigs',
    'stopFailoverControllers',
    'deleteFailoverControllers',
    'stopStandbyNameNode',
    'stopNameNode',
    'restoreHDFSConfigs',
    'enableSecondaryNameNode',
    'stopJournalNodes',
    'deleteJournalNodes',
    'deleteAdditionalNameNode',
    'startAllServices'
  ],

  loadStep: function () {
    this.initData();
    this.clearStep();
    this.loadTasks();
    this.addObserver('tasks.@each.status', this, 'onTaskStatusChange');
    this.onTaskStatusChange();
  },

  initData: function () {
    this.loadMasterComponentHosts();
    this.loadFailedTask();
    this.loadHdfsClientHosts();
  },

  setCommandsAndTasks: function(tmpTasks) {
    var fTask = this.get('failedTask');
    var newCommands = [];
    var newTasks = [];
    var index = [
      'deleteSNameNode',
      'startAllServices',
      'reconfigureHBase',
      'startZKFC',
      'installZKFC',
      'startSecondNameNode',
      'startNameNode',
      'startZooKeeperServers',
      'reconfigureHDFS',
      'disableSNameNode',
      'startJournalNodes',
      'installJournalNodes',
      'installNameNode',
      'stopAllServices'
    ].indexOf(fTask.command);

    if(index > 6){
      --index;
    }
    newCommands = this.get('commands').splice(index);
    this.set('commands', newCommands);
    newTasks = tmpTasks.splice(index);
    this.set('tasks', newTasks);
  },

  clearStep: function () {
    this.set('isSubmitDisabled', true);
    this.set('tasks', []);
    this.set('logs', []);
    this.set('currentRequestIds', []);
    var commands = this.get('commands');
    var tmpTasks = [];
    for (var i = 0; i < commands.length; i++) {
      tmpTasks.pushObject(Ember.Object.create({
        title: Em.I18n.t('admin.highAvailability.rollback.task' + i + '.title'),
        status: 'PENDING',
        id: i,
        command: commands[i],
        showRetry: false,
        name: Em.I18n.t('admin.highAvailability.rollback.task' + i + '.title'),
        displayName: Em.I18n.t('admin.highAvailability.rollback.task' + i + '.title'),
        progress: 0,
        isRunning: false,
        hosts: []
      }));
    }
    this.setCommandsAndTasks(tmpTasks);
  },

  onTaskStatusChange: function () {
    if (!this.get('tasks').someProperty('status', 'IN_PROGRESS') && !this.get('tasks').someProperty('status', 'QUEUED') && !this.get('tasks').someProperty('status', 'FAILED')) {
      var nextTask = this.get('tasks').findProperty('status', 'PENDING');
      if (nextTask) {
        this.set('status', 'IN_PROGRESS');
        this.setTaskStatus(nextTask.get('id'), 'QUEUED');
        this.set('currentTaskId', nextTask.get('id'));
        this.runTask(nextTask.get('id'));
      } else {
        this.set('status', 'COMPLETED');
        this.set('isSubmitDisabled', false);
      }
    } else if (this.get('tasks').someProperty('status', 'FAILED') || this.get('tasks').someProperty('status', 'TIMEDOUT') || this.get('tasks').someProperty('status', 'ABORTED')) {
      this.set('status', 'FAILED');
      this.get('tasks').findProperty('status', 'FAILED').set('showRetry', true);
    }

    var statuses = this.get('tasks').mapProperty('status');
    var requestIds = this.get('currentRequestIds');
    this.saveTasksStatuses(statuses);
    this.saveRequestIds(requestIds);
    App.clusterStatus.setClusterStatus({
      clusterName: this.get('content.cluster.name'),
      clusterState: 'HIGH_AVAILABILITY_ROLLBACK',
      wizardControllerName: this.get('content.controllerName'),
      localdb: App.db.data
    });
  },

  saveTasksStatuses: function(statuses){
    App.db.setHighAvailabilityWizardTasksStatuses(statuses);
    //this.set('content.tasksStatuses', statuses);
  },

  loadTasksStatuses: function(){
    var statuses = App.db.getHighAvailabilityWizardTasksStatuses();
    //this.set('content.tasksStatuses', statuses);
  },

  loadFailedTask: function(){
    var failedTask = App.db.getHighAvailabilityWizardFailedTask();
    this.set('failedTask', failedTask);
  },

  saveRequestIds: function(requestIds){
    App.db.setHighAvailabilityWizardRequestIds(requestIds);
    //this.set('content.requestIds', requestIds);
  },

  loadRequestIds: function(){
    var requestIds = App.db.getHighAvailabilityWizardRequestIds();
    //this.set('content.requestIds', requestIds);
  },

  done: function () {
    if (!this.get('isSubmitDisabled')) {
      this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
      this.get('popup').hide();
      App.router.transitionTo('main.admin.adminHighAvailability');
    }
  },

  stopAllServices: function(){

  },
  restoreHBaseConfigs: function(){

  },

  stopFailoverControllers: function(){

  },
  deleteFailoverControllers: function(){

  },
  stopStandbyNameNode: function(){

  },
  stopNameNode: function(){

  },
  restoreHDFSConfigs: function(){
    this.unInstallHDFSClients();
  },
  enableSecondaryNameNode: function(){
    var hostName = this.get('content.masterComponentHosts').findProperty('component', 'SECONDARY_NAMENODE').hostName;
    this.installComponent('SECONDARY_NAMENODE', hostName, hostName.length);
  },
  stopJournalNodes: function(){
    var hostNames = this.get('content.masterComponentHosts').filterProperty('component', 'JOURNALNODE').mapProperty('hostName');
    this.stopComponent('JOURNALNODE', hostNames);
  },
  deleteJournalNodes: function(){

  },
  deleteAdditionalNameNode: function(){

  },
  startAllServices: function(){

  },

  onLoadHbaseConfigs: function (data) {
    var hbaseSiteProperties = data.items.findProperty('type', 'hbase-site').properties;
    App.ajax.send({
      name: 'admin.high_availability.save_configs',
      sender: this,
      data: {
        siteName: 'hbase-site',
        properties: hbaseSiteProperties
      },
      success: 'onTaskCompleted',
      error: 'onTaskError'
    });
  },

  stopComponent: function (componentName, hostName) {
    if (!(hostName instanceof Array)) {
      hostName = [hostName];
    }
    for (var i = 0; i < hostName.length; i++) {
      App.ajax.send({
        name: 'admin.high_availability.stop_component',
        sender: this,
        data: {
          hostName: hostName[i],
          componentName: componentName,
          displayName: App.format.role(componentName),
          taskNum: hostName.length
        },
        success: 'startPolling',
        error: 'onTaskError'
      });
    }
  },

  onDeletedHDFSClient: function () {
    var deletedHdfsClients = this.get('deletedHdfsClients');
    var hostName = this.get("content.hdfsClientHostNames");
    var notDeletedHdfsClients = hostName.length - deletedHdfsClients;
    if (notDeletedHdfsClients > 1 && hostName.length != 1 ) {
      this.set('deletedHdfsClients', deletedHdfsClients+1);
      return;
    }
    this.loadConfigTag("hdfsSiteTag");
    this.loadConfigTag("coreSiteTag");
    var hdfsSiteTag = this.get("content.hdfsSiteTag");
    var coreSiteTag = this.get("content.coreSiteTag");
    App.ajax.send({
      name: 'admin.high_availability.load_configs',
      sender: this,
      data: {
        hdfsSiteTag: hdfsSiteTag,
        coreSiteTag: coreSiteTag
      },
      success: 'onLoadConfigs',
      error: 'onTaskError'
    });
  },

  onLoadConfigs: function (data) {
    this.set('configsSaved', false);
    App.ajax.send({
      name: 'admin.high_availability.save_configs',
      sender: this,
      data: {
        siteName: 'hdfs-site',
        properties: data.items.findProperty('type', 'hdfs-site').properties
      },
      success: 'onHdfsConfigsSaved',
      error: 'onTaskError'
    });
    App.ajax.send({
      name: 'admin.high_availability.save_configs',
      sender: this,
      data: {
        siteName: 'core-site',
        properties: data.items.findProperty('type', 'core-site').properties
      },
      success: 'onHdfsConfigsSaved',
      error: 'onTaskError'
    });
  },

  onHdfsConfigsSaved: function () {
    if (!this.get('configsSaved')) {
      this.set('configsSaved', true);
      return;
    }
    this.onTaskCompleted();
  },

  unInstallHDFSClients: function () {
    var hostName = this.get("content.hdfsClientHostNames");
    for (var i = 0; i < hostName.length; i++) {
      App.ajax.send({
        name: 'admin.high_availability.delete_component',
        sender: this,
        data: {
          componentName: 'HDFS_CLIENT',
          hostName: hostName[i]
        },
        success: 'onDeletedHDFSClient',
        error: 'onTaskError'
      });
    }
  },

  unInstallComponent: function (componentName, hostName) {
    if (!(hostName instanceof Array)) {
      hostName = [hostName];
    }
    var hostComponents = [];
    for (var i = 0; i < hostName.length; i++) {
      hostComponents = App.HostComponent.find().filterProperty('componentName', componentName);
      if (!hostComponents.length || !hostComponents.mapProperty('host.hostName').contains(hostName[i])) {
        App.ajax.send({
          name: 'admin.high_availability.maintenance_mode',
          sender: this,
          data: {
            hostName: hostName[i],
            componentName: componentName,
            taskNum: hostName.length
          },
          success: 'onMaintenanceComponent',
          error: 'onTaskError'
        });
      } else {
        var taskNum = hostName.length;
        this.deleteComponent(componentName, hostName[i], taskNum);
      }
    }
  },

  onMaintenanceComponent: function () {
    var hostName = arguments[2].hostName;
    var componentName = arguments[2].componentName;
    var taskNum = arguments[2].taskNum;
    this.deleteComponent(componentName, hostName, taskNum);
  },

  deleteComponent: function (componentName, hostName, taskNum) {
    if (!(hostName instanceof Array)) {
      hostName = [hostName];
    }
    this.set('numOfDelOperations', hostName.length);
    for (var i = 0; i < hostName.length; i++) {
      App.ajax.send({
        name: 'admin.high_availability.delete_component',
        sender: this,
        data: {
          componentName: componentName,
          hostName: hostName[i]
        },
        success: 'onDeleteComplete',
        error: 'onTaskError'
      });
    }
  },

  onDeleteComplete: function () {
    var leftOp = this.get('numOfDelOperations');
    if(leftOp > 1){
      this.set('numOfDelOperations', leftOp-1);
      return;
    }
    this.onTaskCompleted();
  }

});
<commit_msg>AMBARI-3165. NameNode HA wizard (rollback): Create API calls for StopAllServices, Restore HBaseConfigs, Stop ZKFC<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var App = require('app');
require('controllers/main/admin/highAvailability/progress_controller');

App.HighAvailabilityRollbackController = App.HighAvailabilityProgressPageController.extend({

  name: "highAvailabilityRollbackController",

  failedTask: null,
  configsSaved: false,
  deletedHdfsClients: 0,
  numOfDelOperations: 0,

  content: Em.Object.create({
    masterComponentHosts: null
  }),

  commands: [
    'stopAllServices',
    'restoreHBaseConfigs',
    'stopFailoverControllers',
    'deleteFailoverControllers',
    'stopStandbyNameNode',
    'stopNameNode',
    'restoreHDFSConfigs',
    'enableSecondaryNameNode',
    'stopJournalNodes',
    'deleteJournalNodes',
    'deleteAdditionalNameNode',
    'startAllServices'
  ],

  loadStep: function () {
    this.initData();
    this.clearStep();
    this.loadTasks();
    this.addObserver('tasks.@each.status', this, 'onTaskStatusChange');
    this.onTaskStatusChange();
  },

  initData: function () {
    this.loadMasterComponentHosts();
    this.loadFailedTask();
    this.loadHdfsClientHosts();
  },

  setCommandsAndTasks: function(tmpTasks) {
    var fTask = this.get('failedTask');
    var newCommands = [];
    var newTasks = [];
    var index = [
      'deleteSNameNode',
      'startAllServices',
      'reconfigureHBase',
      'startZKFC',
      'installZKFC',
      'startSecondNameNode',
      'startNameNode',
      'startZooKeeperServers',
      'reconfigureHDFS',
      'disableSNameNode',
      'startJournalNodes',
      'installJournalNodes',
      'installNameNode',
      'stopAllServices'
    ].indexOf(fTask.command);

    if(index > 6){
      --index;
    }
    newCommands = this.get('commands').splice(index);
    this.set('commands', newCommands);
    newTasks = tmpTasks.splice(index);
    this.set('tasks', newTasks);
  },

  clearStep: function () {
    this.set('isSubmitDisabled', true);
    this.set('tasks', []);
    this.set('logs', []);
    this.set('currentRequestIds', []);
    var commands = this.get('commands');
    var tmpTasks = [];
    for (var i = 0; i < commands.length; i++) {
      tmpTasks.pushObject(Ember.Object.create({
        title: Em.I18n.t('admin.highAvailability.rollback.task' + i + '.title'),
        status: 'PENDING',
        id: i,
        command: commands[i],
        showRetry: false,
        name: Em.I18n.t('admin.highAvailability.rollback.task' + i + '.title'),
        displayName: Em.I18n.t('admin.highAvailability.rollback.task' + i + '.title'),
        progress: 0,
        isRunning: false,
        hosts: []
      }));
    }
    this.setCommandsAndTasks(tmpTasks);
  },

  onTaskStatusChange: function () {
    if (!this.get('tasks').someProperty('status', 'IN_PROGRESS') && !this.get('tasks').someProperty('status', 'QUEUED') && !this.get('tasks').someProperty('status', 'FAILED')) {
      var nextTask = this.get('tasks').findProperty('status', 'PENDING');
      if (nextTask) {
        this.set('status', 'IN_PROGRESS');
        this.setTaskStatus(nextTask.get('id'), 'QUEUED');
        this.set('currentTaskId', nextTask.get('id'));
        this.runTask(nextTask.get('id'));
      } else {
        this.set('status', 'COMPLETED');
        this.set('isSubmitDisabled', false);
      }
    } else if (this.get('tasks').someProperty('status', 'FAILED') || this.get('tasks').someProperty('status', 'TIMEDOUT') || this.get('tasks').someProperty('status', 'ABORTED')) {
      this.set('status', 'FAILED');
      this.get('tasks').findProperty('status', 'FAILED').set('showRetry', true);
    }

    var statuses = this.get('tasks').mapProperty('status');
    var requestIds = this.get('currentRequestIds');
    this.saveTasksStatuses(statuses);
    this.saveRequestIds(requestIds);
    App.clusterStatus.setClusterStatus({
      clusterName: this.get('content.cluster.name'),
      clusterState: 'HIGH_AVAILABILITY_ROLLBACK',
      wizardControllerName: this.get('content.controllerName'),
      localdb: App.db.data
    });
  },

  saveTasksStatuses: function(statuses){
    App.db.setHighAvailabilityWizardTasksStatuses(statuses);
    this.set('content.tasksStatuses', statuses);
  },

  loadTasksStatuses: function(){
    var statuses = App.db.getHighAvailabilityWizardTasksStatuses();
    this.set('content.tasksStatuses', statuses);
  },

  loadFailedTask: function(){
    var failedTask = App.db.getHighAvailabilityWizardFailedTask();
    this.set('failedTask', failedTask);
  },

  saveRequestIds: function(requestIds){
    App.db.setHighAvailabilityWizardRequestIds(requestIds);
    this.set('content.requestIds', requestIds);
  },

  loadRequestIds: function(){
    var requestIds = App.db.getHighAvailabilityWizardRequestIds();
    this.set('content.requestIds', requestIds);
  },

  done: function () {
    if (!this.get('isSubmitDisabled')) {
      this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
      this.get('popup').hide();
      App.router.transitionTo('main.admin.adminHighAvailability');
    }
  },

  stopAllServices: function(){
    App.ajax.send({
      name: 'admin.high_availability.stop_all_services',
      sender: this,
      success: 'startPolling',
      error: 'onTaskError'
    });
  },
  restoreHBaseConfigs: function(){
    this.loadConfigTag("hbaseSiteTag");
    var hbaseSiteTag = this.get("content.hbaseSiteTag");
    App.ajax.send({
      name: 'admin.high_availability.load_hbase_configs',
      sender: this,
      data: {
        hbaseSiteTag: hbaseSiteTag
      },
      success: 'onLoadHbaseConfigs',
      error: 'onTaskError'
    });
  },

  stopFailoverControllers: function(){
    var hostNames = this.get('content.masterComponentHosts').filterProperty('component', 'NAMENODE').mapProperty('hostName');
    this.stopComponent('ZKFC', hostNames);
  },
  deleteFailoverControllers: function(){

  },
  stopStandbyNameNode: function(){

  },
  stopNameNode: function(){

  },
  restoreHDFSConfigs: function(){
    this.unInstallHDFSClients();
  },
  enableSecondaryNameNode: function(){
    var hostName = this.get('content.masterComponentHosts').findProperty('component', 'SECONDARY_NAMENODE').hostName;
    this.installComponent('SECONDARY_NAMENODE', hostName, hostName.length);
  },
  stopJournalNodes: function(){
    var hostNames = this.get('content.masterComponentHosts').filterProperty('component', 'JOURNALNODE').mapProperty('hostName');
    this.stopComponent('JOURNALNODE', hostNames);
  },
  deleteJournalNodes: function(){

  },
  deleteAdditionalNameNode: function(){

  },
  startAllServices: function(){

  },

  onLoadHbaseConfigs: function (data) {
    var hbaseSiteProperties = data.items.findProperty('type', 'hbase-site').properties;
    App.ajax.send({
      name: 'admin.high_availability.save_configs',
      sender: this,
      data: {
        siteName: 'hbase-site',
        properties: hbaseSiteProperties
      },
      success: 'onTaskCompleted',
      error: 'onTaskError'
    });
  },

  stopComponent: function (componentName, hostName) {
    if (!(hostName instanceof Array)) {
      hostName = [hostName];
    }
    for (var i = 0; i < hostName.length; i++) {
      App.ajax.send({
        name: 'admin.high_availability.stop_component',
        sender: this,
        data: {
          hostName: hostName[i],
          componentName: componentName,
          displayName: App.format.role(componentName),
          taskNum: hostName.length
        },
        success: 'startPolling',
        error: 'onTaskError'
      });
    }
  },

  onDeletedHDFSClient: function () {
    var deletedHdfsClients = this.get('deletedHdfsClients');
    var hostName = this.get("content.hdfsClientHostNames");
    var notDeletedHdfsClients = hostName.length - deletedHdfsClients;
    if (notDeletedHdfsClients > 1 && hostName.length != 1 ) {
      this.set('deletedHdfsClients', deletedHdfsClients+1);
      return;
    }
    this.loadConfigTag("hdfsSiteTag");
    this.loadConfigTag("coreSiteTag");
    var hdfsSiteTag = this.get("content.hdfsSiteTag");
    var coreSiteTag = this.get("content.coreSiteTag");
    App.ajax.send({
      name: 'admin.high_availability.load_configs',
      sender: this,
      data: {
        hdfsSiteTag: hdfsSiteTag,
        coreSiteTag: coreSiteTag
      },
      success: 'onLoadConfigs',
      error: 'onTaskError'
    });
  },

  onLoadConfigs: function (data) {
    this.set('configsSaved', false);
    App.ajax.send({
      name: 'admin.high_availability.save_configs',
      sender: this,
      data: {
        siteName: 'hdfs-site',
        properties: data.items.findProperty('type', 'hdfs-site').properties
      },
      success: 'onHdfsConfigsSaved',
      error: 'onTaskError'
    });
    App.ajax.send({
      name: 'admin.high_availability.save_configs',
      sender: this,
      data: {
        siteName: 'core-site',
        properties: data.items.findProperty('type', 'core-site').properties
      },
      success: 'onHdfsConfigsSaved',
      error: 'onTaskError'
    });
  },

  onHdfsConfigsSaved: function () {
    if (!this.get('configsSaved')) {
      this.set('configsSaved', true);
      return;
    }
    this.onTaskCompleted();
  },

  unInstallHDFSClients: function () {
    var hostName = this.get("content.hdfsClientHostNames");
    for (var i = 0; i < hostName.length; i++) {
      App.ajax.send({
        name: 'admin.high_availability.delete_component',
        sender: this,
        data: {
          componentName: 'HDFS_CLIENT',
          hostName: hostName[i]
        },
        success: 'onDeletedHDFSClient',
        error: 'onTaskError'
      });
    }
  },

  unInstallComponent: function (componentName, hostName) {
    if (!(hostName instanceof Array)) {
      hostName = [hostName];
    }
    for (var i = 0; i < hostName.length; i++) {
      App.ajax.send({
        name: 'admin.high_availability.maintenance_mode',
        sender: this,
        data: {
          hostName: hostName[i],
          componentName: componentName,
          taskNum: hostName.length
        },
        success: 'onMaintenanceComponent',
        error: 'onTaskError'
      });
    }
  },

  onMaintenanceComponent: function () {
    var hostName = arguments[2].hostName;
    var componentName = arguments[2].componentName;
    this.deleteComponent(componentName, hostName);
  },

  deleteComponent: function (componentName, hostName) {
    if (!(hostName instanceof Array)) {
      hostName = [hostName];
    }
    this.set('numOfDelOperations', hostName.length);
    for (var i = 0; i < hostName.length; i++) {
      App.ajax.send({
        name: 'admin.high_availability.delete_component',
        sender: this,
        data: {
          componentName: componentName,
          hostName: hostName[i]
        },
        success: 'onDeleteComplete',
        error: 'onTaskError'
      });
    }
  },

  onDeleteComplete: function () {
    var leftOp = this.get('numOfDelOperations');
    if(leftOp > 1){
      this.set('numOfDelOperations', leftOp-1);
      return;
    }
    this.onTaskCompleted();
  }

});
<|endoftext|>


<commit_before>// Copyright 2016-2018, University of Colorado Boulder

/**
 * Convenience subtype of Property that constrains values to be true or false.
 * Truthy/falsy values are considered invalid.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const axon = require( 'AXON/axon' );
  const BooleanIO = require( 'TANDEM/types/BooleanIO' );
  const Property = require( 'AXON/Property' );
  const PropertyIO = require( 'AXON/PropertyIO' );

  // constants
  const BooleanPropertyIO = PropertyIO( BooleanIO );

  class BooleanProperty extends Property {

    /**
     * @param {boolean} value - initial value
     * @param {Object} [options]
     * @constructor
     */
    constructor( value, options ) {

      options = options || {};

      assert && assert( !options.isValidValue, 'isValidValue is not supported by BooleanProperty' );
      assert && assert( !options.validValues, 'validValues is not supported by BooleanProperty' );
      assert && assert( !options.valueType, 'valueType is set by BooleanProperty' );
      options.valueType = 'boolean';  // BooleanProperty requires values to be primitive booleans

      assert && assert( !options.hasOwnProperty( 'phetioType' ), 'phetioType is set by BooleanProperty' );
      options.phetioType = BooleanPropertyIO;

      super( value, options );
    }
  }

  return axon.register( 'BooleanProperty', BooleanProperty );
} );<commit_msg>Fixed: do not mutate the passed-in options, see https://github.com/phetsims/dot/issues/88<commit_after>// Copyright 2016-2018, University of Colorado Boulder

/**
 * Convenience subtype of Property that constrains values to be true or false.
 * Truthy/falsy values are considered invalid.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const axon = require( 'AXON/axon' );
  const BooleanIO = require( 'TANDEM/types/BooleanIO' );
  const Property = require( 'AXON/Property' );
  const PropertyIO = require( 'AXON/PropertyIO' );

  // constants
  const BooleanPropertyIO = PropertyIO( BooleanIO );

  class BooleanProperty extends Property {

    /**
     * @param {boolean} value - initial value
     * @param {Object} [options]
     * @constructor
     */
    constructor( value, options ) {

      assert && assert( !options || !options.hasOwnProperty( 'isValidValue' ), 'isValidValue is not supported by BooleanProperty' );
      assert && assert( !options || !options.hasOwnProperty( 'validValues' ), 'validValues is not supported by BooleanProperty' );
      assert && assert( !options || !options.hasOwnProperty( 'valueType' ), 'valueType is set by BooleanProperty' );
      assert && assert( !options || !options.hasOwnProperty( 'phetioType' ), 'phetioType is set by BooleanProperty' );

      super( value, _.extend( {
        valueType: 'boolean', // BooleanProperty requires values to be primitive booleans
        phetioType: BooleanPropertyIO
      } ) );
    }
  }

  return axon.register( 'BooleanProperty', BooleanProperty );
} );<|endoftext|>


<commit_before>/*
 * Input Manager for desktop and mobile browsers
 */

function KeyboardInputManager() {
  this.events = {};
  this.listen();
}

KeyboardInputManager.prototype.on = function (event, callback) {
  if (!this.events[event]) {
    this.events[event] = [];
  }
  this.events[event].push(callback);
};

KeyboardInputManager.prototype.emit = function (event, data) {
  devdebug("Emit event '" + event + (data ?  ("': " + JSON.stringify(data)) : ""));
  var callbacks = this.events[event];
  if (callbacks) {
    callbacks.forEach(function (callback) {
      callback(data);
    });
  }
};

KeyboardInputManager.prototype.bindButtonPress = function (selector, fn) {
  var button = document.querySelector(selector);
  button.addEventListener("click", fn.bind(this));
  button.addEventListener(this.eventTouchend, fn.bind(this));
};

KeyboardInputManager.prototype.listen = function(){
  var colorSaveOption        = document.getElementById("cbsavecolor");
  var languageSelection      = document.querySelector(".ln-selection");
  var questionnaireSelection = document.querySelector(".questionnaires-selection");

  languageSelection.addEventListener("change",      this.selectTranslation.bind(this));
  colorSaveOption.addEventListener("change",        this.setOption.bind(this));
  questionnaireSelection.addEventListener("change", this.selectQuestionnaire.bind(this));

  this.bindButtonPress(".button-random",    this.newQuestion);
  this.bindButtonPress(".button-menu",      this.showMenu);
  this.bindButtonPress(".button-start",     this.showQuestion);
  this.bindButtonPress(".button-newcolor",  this.newColor);
  this.bindButtonPress(".button-reset",     this.resetApplicationManager);
};

KeyboardInputManager.prototype.selectTranslation = function(event){
  var ln = event.target.value;
  this.emit("translateUI", ln);
};

KeyboardInputManager.prototype.selectQuestionnaire = function(event) {
  var questionnaire = event.target.value;
  this.emit("selectQuestionnaire", questionnaire);
};

KeyboardInputManager.prototype.newQuestion = function(event){
  event.preventDefault();
  this.emit("newQuestion");
};

KeyboardInputManager.prototype.showMenu = function(event){
  event.preventDefault();
  this.emit("showMenu");
};

KeyboardInputManager.prototype.showQuestion = function(event){
  event.preventDefault();
  this.emit("showQuestion");
};

KeyboardInputManager.prototype.newColor = function(event){
  event.preventDefault();
  this.emit("newColor");
};

KeyboardInputManager.prototype.setOption = function(event){
  var data = {};
  data.type   = "saveColor";
  data.value  = event.target.checked;
  event.preventDefault();
  this.emit("setOption", data);
};

KeyboardInputManager.prototype.resetApplicationManager = function(event){
  event.preventDefault();
  this.emit("resetApplicationManager");
};
<commit_msg>Added indicator for main menu state<commit_after>/*
 * Input Manager for desktop and mobile browsers
 */

function KeyboardInputManager() {
  this.events = {};
  this.listen();
  mainMenuVisible = true;
}

KeyboardInputManager.prototype.on = function (event, callback) {
  if (!this.events[event]) {
    this.events[event] = [];
  }
  this.events[event].push(callback);
};

KeyboardInputManager.prototype.emit = function (event, data) {
  devdebug("Emit event '" + event + (data ?  ("': " + JSON.stringify(data)) : ""));
  var callbacks = this.events[event];
  if (callbacks) {
    callbacks.forEach(function (callback) {
      callback(data);
    });
  }
};

KeyboardInputManager.prototype.bindButtonPress = function (selector, fn) {
  var button = document.querySelector(selector);
  button.addEventListener("click", fn.bind(this));
  button.addEventListener(this.eventTouchend, fn.bind(this));
};

KeyboardInputManager.prototype.listen = function(){
  var colorSaveOption        = document.getElementById("cbsavecolor");
  var languageSelection      = document.querySelector(".ln-selection");
  var questionnaireSelection = document.querySelector(".questionnaires-selection");

  languageSelection.addEventListener("change",      this.selectTranslation.bind(this));
  colorSaveOption.addEventListener("change",        this.setOption.bind(this));
  questionnaireSelection.addEventListener("change", this.selectQuestionnaire.bind(this));

  this.bindButtonPress(".button-random",      this.newQuestion);
  this.bindButtonPress(".button-menu",        this.showMenu);
  this.bindButtonPress(".button-start",       this.showQuestion);
  this.bindButtonPress(".button-description", this.showModal);
  this.bindButtonPress(".modal-close",        this.closeModal);

  this.bindButtonPress(".button-newcolor",  this.newColor);
  this.bindButtonPress(".button-reset",     this.resetApplicationManager);

};

KeyboardInputManager.prototype.selectTranslation = function(event){
  var ln = event.target.value;
  this.emit("translateUI", ln);
};

KeyboardInputManager.prototype.selectQuestionnaire = function(event) {
  var questionnaire = event.target.value;
  this.emit("selectQuestionnaire", questionnaire);
};

KeyboardInputManager.prototype.newQuestion = function(event){
  event.preventDefault();
  this.emit("newQuestion");
};

KeyboardInputManager.prototype.showMenu = function(event){
  event.preventDefault();
  mainMenuVisible = true;
  this.emit("showMenu");
};

KeyboardInputManager.prototype.showQuestion = function(event){
  event.preventDefault();
  mainMenuVisible = false;
  this.emit("showQuestion");
};

KeyboardInputManager.prototype.showModal = function(event){
  mainMenuVisible = false;
};

KeyboardInputManager.prototype.closeModal = function(event){
  mainMenuVisible = true;
};

KeyboardInputManager.prototype.newColor = function(event){
  event.preventDefault();
  this.emit("newColor");
};

KeyboardInputManager.prototype.setOption = function(event){
  var data = {};
  data.type   = "saveColor";
  data.value  = event.target.checked;
  event.preventDefault();
  this.emit("setOption", data);
};

KeyboardInputManager.prototype.resetApplicationManager = function(event){
  event.preventDefault();
  this.emit("resetApplicationManager");
};
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Corpuslinguistic working group Humboldt University Berlin.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
window.annis_gui_components_codemirror_AqlCodeEditor = function() {

    var connector = this;
    var rootDiv = this.getElement(this.getConnectorId());

    var changeDelayTimerID = null;
    var lastSentText = "";

    var changeDelayTime = 500;

    var cmTextArea = CodeMirror(rootDiv,
    {
      mode: 'aql'
    });

    function changeDelayCallback ()
    {
      var current = cmTextArea.getValue();
      if(lastSentText !== current)
      {
        var cursor = cmTextArea.getCursor();
        // calculate the absolute cursor position
        var absPos = 0;
        for(i=0; i < cursor.line; i++)
        {
          absPos += cmTextArea.getLine(i).length;
          absPos++; // add one for the newline
        }
        absPos += cursor.ch;

        connector.textChanged(cmTextArea.getValue(), absPos);
        lastSentText = current;
      }
    };

    this.onStateChange = function()
    {
      cmTextArea.setValue(connector.getState().text);
    };

    this.setChangeDelayTime = function(newDelayTime) {
      changeDelayTime = newDelayTime;
    };

    this.updateText = function(newText) {

    };

    cmTextArea.on("change", function(instance, changeObj)
    {
      if(changeDelayTimerID)
      {
        window.clearTimeout(changeDelayTimerID);
      }
      changeDelayTimerID = window.setTimeout(changeDelayCallback, changeDelayTime);
    });

};

<commit_msg>don't reset cursor on state change<commit_after>/*
 * Copyright 2013 Corpuslinguistic working group Humboldt University Berlin.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
window.annis_gui_components_codemirror_AqlCodeEditor = function() {

    var connector = this;
    var rootDiv = this.getElement(this.getConnectorId());

    var changeDelayTimerID = null;
    var lastSentText = "";

    var changeDelayTime = 500;

    var cmTextArea = CodeMirror(rootDiv,
    {
      mode: 'aql'
    });

    function changeDelayCallback ()
    {
      var current = cmTextArea.getValue();
      if(lastSentText !== current)
      {
        var cursor = cmTextArea.getCursor();
        // calculate the absolute cursor position
        var absPos = 0;
        for(i=0; i < cursor.line; i++)
        {
          absPos += cmTextArea.getLine(i).length;
          absPos++; // add one for the newline
        }
        absPos += cursor.ch;

        connector.textChanged(cmTextArea.getValue(), absPos);
        lastSentText = current;
      }
    };

    this.onStateChange = function()
    {
      var cursor = cmTextArea.getCursor();
      if(cmTextArea.getValue() !== connector.getState().text)
      {
        cmTextArea.setValue(connector.getState().text);

        // restore the cursor position
        cmTextArea.setCursor(cursor);
      }
    };

    this.setChangeDelayTime = function(newDelayTime) {
      changeDelayTime = newDelayTime;
    };

    this.updateText = function(newText) {

    };

    cmTextArea.on("change", function(instance, changeObj)
    {
      if(changeDelayTimerID)
      {
        window.clearTimeout(changeDelayTimerID);
      }
      changeDelayTimerID = window.setTimeout(changeDelayCallback, changeDelayTime);
    });

};

<|endoftext|>


<commit_before>/*
 * Copyright 2013 Corpuslinguistic working group Humboldt University Berlin.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
window.annis_gui_components_codemirror_AqlCodeEditor = function() {

    var connector = this;
    var rootDiv = this.getElement(this.getConnectorId());

    var changeDelayTimerID = null;
    var lastSentText = "";

    var changeDelayTime = 500;

    var cmTextArea = CodeMirror(rootDiv,
    {
      mode: 'aql'
    });

    function changeDelayCallback ()
    {
      var current = cmTextArea.getValue();
      if(lastSentText !== current)
      {
        var cursor = cmTextArea.getCursor();
        // calculate the absolute cursor position
        var absPos = 0;
        for(i=0; i < cursor.line; i++)
        {
          absPos += cmTextArea.getLine(i).length;
          absPos++; // add one for the newline
        }
        absPos += cursor.ch;

        connector.textChanged(cmTextArea.getValue(), absPos);
        lastSentText = current;
      }
    };

    this.onStateChange = function()
    {
      var cursor = cmTextArea.getCursor();
      if(cmTextArea.getValue() !== connector.getState().text)
      {
        cmTextArea.setValue(connector.getState().text);

        // restore the cursor position
        cmTextArea.setCursor(cursor);
      }
    };

    this.setChangeDelayTime = function(newDelayTime) {
      changeDelayTime = newDelayTime;
    };

    this.updateText = function(newText) {

    };

    cmTextArea.on("change", function(instance, changeObj)
    {
      if(changeDelayTimerID)
      {
        window.clearTimeout(changeDelayTimerID);
      }
      changeDelayTimerID = window.setTimeout(changeDelayCallback, changeDelayTime);
    });

};

<commit_msg>remove empty function<commit_after>/*
 * Copyright 2013 Corpuslinguistic working group Humboldt University Berlin.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
window.annis_gui_components_codemirror_AqlCodeEditor = function() {

    var connector = this;
    var rootDiv = this.getElement(this.getConnectorId());

    var changeDelayTimerID = null;
    var lastSentText = "";

    var changeDelayTime = 500;

    var cmTextArea = CodeMirror(rootDiv,
    {
      mode: 'aql'
    });

    function changeDelayCallback ()
    {
      var current = cmTextArea.getValue();
      if(lastSentText !== current)
      {
        var cursor = cmTextArea.getCursor();
        // calculate the absolute cursor position
        var absPos = 0;
        for(i=0; i < cursor.line; i++)
        {
          absPos += cmTextArea.getLine(i).length;
          absPos++; // add one for the newline
        }
        absPos += cursor.ch;

        connector.textChanged(cmTextArea.getValue(), absPos);
        lastSentText = current;
      }
    };

    this.onStateChange = function()
    {
      var cursor = cmTextArea.getCursor();
      if(cmTextArea.getValue() !== connector.getState().text)
      {
        cmTextArea.setValue(connector.getState().text);

        // restore the cursor position
        cmTextArea.setCursor(cursor);
      }
    };

    this.setChangeDelayTime = function(newDelayTime) {
      changeDelayTime = newDelayTime;
    };

    cmTextArea.on("change", function(instance, changeObj)
    {
      if(changeDelayTimerID)
      {
        window.clearTimeout(changeDelayTimerID);
      }
      changeDelayTimerID = window.setTimeout(changeDelayCallback, changeDelayTime);
    });

};

<|endoftext|>


<commit_before>//viewmodel for the assess page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AssessTitle");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AssessTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("HomeManual");}, gvm);
    gvm.foundProjects = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FoundProjects");}, gvm);
    gvm.selectCourse = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SelectCourse");}, gvm);

    // Pagination i18n bindings
    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    // Table i18n bindings
    gvm.codeTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CodeTableTitle");}, gvm);
    gvm.nameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NameTableTitle");}, gvm);
    gvm.descTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("DescTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    gvm.currentCourseId = null;

    gvm.updateDropdowns = function() {
        $.getJSON('api/lastdropdownchoice/' + gvm.userId, function(data) {
            if(!$.isEmptyObject(data)) {
                $.each(data, function(i, item) {
                    $(".btn-location span:first").text(item.location);
                    $(".btn-training span:first").text(item.training);
                    $(".btn-course span:first").text(item.course);
                    gvm.updateLocations();
                    loadTablePage(item.courseid, 1);
                });
            } else {
                gvm.updateLocations();
            }
        });
    }

    gvm.saveLastSelectedDropdowns = function() {
        data = {};
        data["location"] = $(".btn-location span:first").text();
        data["training"] = $(".btn-training span:first").text();
        data["course"] = $(".btn-course span:first").text();
        data["courseid"] = gvm.currentCourseId;
        data["user"] = gvm.userId;
        console.log(data);
        $.ajax({
            type: "POST",
            url: "/api/savedropdowns",
            data: data,
            success: function() {
                console.log("success");
            }
        })
    }

    gvm.updateLocations = function() {
        $.getJSON('/api/locations', function(data) {
            gvm.availableLocations.removeAll();
            $.each(data, function(i, item) {
                /* Put item in list */
                gvm.availableLocations.push(item);

                /* Add listener to listitem */
                $("#locbtn-" + item.id).click(function(){
                    gvm.currentCourseId = null;
                    gvm.updateTrainings(item.id);
                    $(".btn-location span:first").text($(this).text());
                });
            });
        });
    };

    /*
     * Update the training data
     */
    gvm.updateTrainings = function(id) {
        $.getJSON('/api/trainings/' + id, function(data) {
            gvm.availableTrainings.removeAll();
            $.each(data, function(i, item) {
                gvm.availableTrainings.push(item);

                /* Add listener to listitem */
                $("#trainingbtn-" + item.id).click(function(){
                    gvm.currentCourseId = null;
                    gvm.updateCourses(item.id);
                    $(".btn-training span:first").text($(this).text());
                });
            });
        });
    }

    /*
     * Update available courses
     */
    gvm.updateCourses = function(id) {
        $.getJSON('/api/courses/' + id, function(data) {
            gvm.availableCourses.removeAll();
            $.each(data, function(i, item) {
                gvm.availableCourses.push(item);

                /* Add listener to listitem */
                $("#coursebtn-" + item.id).click(function(){
                    $(".btn-course span:first").text($(this).text());
                    gvm.currentCourseId = item.id;
                    loadTablePage(item.id, 1);
                });
            });
        });
    }

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, code, name, desc) {
        // Push data
        var tblOject = {tid: id, tcode: code, tname: name, tdesc: desc};
        gvm.tabledata.push(tblOject);
    }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }
}

function loadTablePage(courseid, pagenr)
{
    $.getJSON('/api/projects/' + courseid + '/page/' + pagenr, function(data){

        /* Clear current table page */
        viewModel.clearTable()

        // Load table data
        $.each(data.data, function(i, item) {
            viewModel.addTableData(item.id, item.code, item.name, item.description);
        });

        /* Let previous en next buttons work */
        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if(data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(courseid, thispagenr);
                });
            }
        });
    });

}

function initPage() {
    viewModel.updateDropdowns();
}<commit_msg>coupling between project and studentlists<commit_after>//viewmodel for the assess page
function pageViewModel(gvm) {
    gvm.userId = -1;
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AssessTitle");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AssessTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("HomeManual");}, gvm);
    gvm.foundProjects = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FoundProjects");}, gvm);
    gvm.selectCourse = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SelectCourse");}, gvm);

    // Pagination i18n bindings
    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    // Table i18n bindings
    gvm.codeTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CodeTableTitle");}, gvm);
    gvm.nameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NameTableTitle");}, gvm);
    gvm.descTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("DescTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    gvm.currentCourseId = null;

    gvm.updateDropdowns = function() {
        $.getJSON('api/lastdropdownchoice/' + gvm.userId, function(data) {
            if(!$.isEmptyObject(data)) {
                $.each(data, function(i, item) {
                    $(".btn-location span:first").text(item.location);
                    $(".btn-training span:first").text(item.training);
                    $(".btn-course span:first").text(item.course);
                    gvm.updateLocations();
                    loadTablePage(item.courseid, 1);
                });
            } else {
                gvm.updateLocations();
            }
        });
    }

    gvm.saveLastSelectedDropdowns = function() {
        data = {};
        data["location"] = $(".btn-location span:first").text();
        data["training"] = $(".btn-training span:first").text();
        data["course"] = $(".btn-course span:first").text();
        data["courseid"] = gvm.currentCourseId;
        data["user"] = gvm.userId;
        console.log(data);
        $.ajax({
            type: "POST",
            url: "/api/savedropdowns",
            data: data,
            success: function() {
                console.log("success");
            }
        })
    }

    gvm.updateLocations = function() {
        $.getJSON('/api/locations', function(data) {
            gvm.availableLocations.removeAll();
            $.each(data, function(i, item) {
                /* Put item in list */
                gvm.availableLocations.push(item);

                /* Add listener to listitem */
                $("#locbtn-" + item.id).click(function(){
                    gvm.currentCourseId = null;
                    gvm.updateTrainings(item.id);
                    $(".btn-location span:first").text($(this).text());
                });
            });
        });
    };

    /*
     * Update the training data
     */
    gvm.updateTrainings = function(id) {
        $.getJSON('/api/trainings/' + id, function(data) {
            gvm.availableTrainings.removeAll();
            $.each(data, function(i, item) {
                gvm.availableTrainings.push(item);

                /* Add listener to listitem */
                $("#trainingbtn-" + item.id).click(function(){
                    gvm.currentCourseId = null;
                    gvm.updateCourses(item.id);
                    $(".btn-training span:first").text($(this).text());
                });
            });
        });
    }

    /*
     * Update available courses
     */
    gvm.updateCourses = function(id) {
        $.getJSON('/api/courses/' + id, function(data) {
            gvm.availableCourses.removeAll();
            $.each(data, function(i, item) {
                gvm.availableCourses.push(item);

                /* Add listener to listitem */
                $("#coursebtn-" + item.id).click(function(){
                    $(".btn-course span:first").text($(this).text());
                    gvm.currentCourseId = item.id;
                    loadTablePage(item.id, 1);
                });
            });
        });
    }

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, code, name, desc) {
        // Push data
        var tblOject = {tid: id, tcode: code, tname: name, tdesc: desc};
        gvm.tabledata.push(tblOject);
    }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }
}

function loadTablePage(courseid, pagenr)
{
    $.getJSON('/api/projects/' + courseid + '/page/' + pagenr, function(data){

        /* Clear current table page */
        viewModel.clearTable()

        // Load table data
        $.each(data.data, function(i, item) {
            viewModel.addTableData(item.id, item.code, item.name, item.description);
        });

        /* Let previous en next buttons work */
        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if(data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(courseid, thispagenr);
                });
            }
        });
    });

}

function initPage() {
    $.getJSON('/api/currentuser', function(data) {
        viewModel.userId = data.id;
        viewModel.updateDropdowns();
    });
}<|endoftext|>