<commit_before>ManageIQ.angular.app.controller('emsCommonFormController', ['$http', '$scope', '$attrs', 'emsCommonFormId', 'miqService', function($http, $scope, $attrs, emsCommonFormId, miqService) {
  var init = function() {
    $scope.emsCommonModel = {
      name: '',
      emstype: '',
      openstack_infra_providers_exist: false,
      provider_id: '',
      zone: '',
      hostname: '',
      default_hostname: '',
      amqp_hostname: '',
      metrics_hostname: '',
      project: '',
      default_api_port: '',
      amqp_api_port: '',
      metrics_port: '',
      api_version: '',
      default_security_protocol: '',
      realm: '',
      security_protocol: '',
      amqp_security_protocol: '',
      provider_region: '',
      default_userid: '',
      default_password: '',
      default_verify: '',
      amqp_userid: '',
      amqp_password: '',
      amqp_verify: '',
      metrics_userid: '',
      metrics_password: '',
      metrics_verify: '',
      ssh_keypair_userid: '',
      ssh_keypair_password: '',
      ssh_keypair_verify: '',
      service_account: '',
      emstype_vm: false,
      ems_common: true,
      azure_tenant_id: '',
      keystone_v3_domain_id: '',
      subscription: '',
      host_default_vnc_port_start: '',
      host_default_vnc_port_end: '',
      event_stream_selection: '',
      ems_controller: ''
    };
    $scope.realmNote = __("Note: Username must be in the format: name@realm");
    $scope.formId = emsCommonFormId;
    $scope.afterGet = false;
    $scope.validateClicked = miqService.validateWithREST;
    $scope.modelCopy = angular.copy( $scope.emsCommonModel );
    $scope.formFieldsUrl = $attrs.formFieldsUrl;
    $scope.createUrl = $attrs.createUrl;
    $scope.updateUrl = $attrs.updateUrl;
    $scope.model = 'emsCommonModel';

    ManageIQ.angular.scope = $scope;

    if (emsCommonFormId == 'new') {
      $scope.newRecord                  = true;

      miqService.sparkleOn();
      $http.get($scope.formFieldsUrl + emsCommonFormId).success(function(data) {
        $scope.emsCommonModel.zone                            = data.zone;
        $scope.emsCommonModel.emstype_vm                      = data.emstype_vm;
        $scope.emsCommonModel.openstack_infra_providers_exist = data.openstack_infra_providers_exist;
        $scope.emsCommonModel.default_api_port                = 5000;
        $scope.emsCommonModel.amqp_api_port                   = 5672;
        $scope.emsCommonModel.api_version                     = 'v2';
        $scope.emsCommonModel.ems_controller                  = data.ems_controller;
        miqService.sparkleOff();
      });
      $scope.afterGet  = true;
      $scope.modelCopy = angular.copy( $scope.emsCommonModel );
    }
    else {
      $scope.newRecord = false;
      miqService.sparkleOn();

      $http.get($scope.formFieldsUrl + emsCommonFormId).success(function(data) {
        $scope.emsCommonModel.name                            = data.name;
        $scope.emsCommonModel.emstype                         = data.emstype;
        $scope.emsCommonModel.zone                            = data.zone;
        $scope.emsCommonModel.hostname                        = data.hostname;
        $scope.emsCommonModel.default_hostname                = data.default_hostname;
        $scope.emsCommonModel.amqp_hostname                   = data.amqp_hostname;
        $scope.emsCommonModel.metrics_hostname                = data.metrics_hostname;
        $scope.emsCommonModel.project                         = data.project;

        $scope.emsCommonModel.openstack_infra_providers_exist = data.openstack_infra_providers_exist;

        $scope.emsCommonModel.provider_id                     = angular.isDefined(data.provider_id) ? data.provider_id.toString() : "";

        $scope.emsCommonModel.default_api_port                = angular.isDefined(data.default_api_port) && data.default_api_port != '' ? data.default_api_port : '5000';
        $scope.emsCommonModel.amqp_api_port                   = angular.isDefined(data.amqp_api_port) && data.amqp_api_port != '' ? data.amqp_api_port : '5672';
        $scope.emsCommonModel.metrics_api_port                = angular.isDefined(data.metrics_api_port) && data.metrics_api_port != '' ? data.metrics_api_port : '';
        $scope.emsCommonModel.api_version                     = data.api_version;
        $scope.emsCommonModel.default_security_protocol       = data.default_security_protocol;
        $scope.emsCommonModel.realm                           = data.realm;
        $scope.emsCommonModel.security_protocol               = data.security_protocol;
        $scope.emsCommonModel.amqp_security_protocol          = data.amqp_security_protocol;
        $scope.emsCommonModel.provider_region                 = data.provider_region;
        $scope.emsCommonModel.default_userid                  = data.default_userid;
        $scope.emsCommonModel.amqp_userid                     = data.amqp_userid;
        $scope.emsCommonModel.metrics_userid                  = data.metrics_userid;

        $scope.emsCommonModel.ssh_keypair_userid              = data.ssh_keypair_userid;

        $scope.emsCommonModel.service_account                 = data.service_account;
        $scope.emsCommonModel.azure_tenant_id                 = data.azure_tenant_id;
        $scope.emsCommonModel.keystone_v3_domain_id           = data.keystone_v3_domain_id;
        $scope.emsCommonModel.subscription                    = data.subscription;

        $scope.emsCommonModel.host_default_vnc_port_start     = data.host_default_vnc_port_start;
        $scope.emsCommonModel.host_default_vnc_port_end       = data.host_default_vnc_port_end;

        $scope.emsCommonModel.ems_controller                  = data.ems_controller;

        if($scope.emsCommonModel.default_userid != '') {
          $scope.emsCommonModel.default_password = $scope.emsCommonModel.default_verify = miqService.storedPasswordPlaceholder;
        }
        if($scope.emsCommonModel.amqp_userid != '') {
          $scope.emsCommonModel.amqp_password = $scope.emsCommonModel.amqp_verify = miqService.storedPasswordPlaceholder;
        }
        if($scope.emsCommonModel.metrics_userid != '') {
          $scope.emsCommonModel.metrics_password = $scope.emsCommonModel.metrics_verify = miqService.storedPasswordPlaceholder;
        }
        if($scope.emsCommonModel.ssh_keypair_userid != '') {
          $scope.emsCommonModel.ssh_keypair_password = $scope.emsCommonModel.ssh_keypair_verify = miqService.storedPasswordPlaceholder;
        }

        $scope.afterGet  = true;
        $scope.modelCopy = angular.copy( $scope.emsCommonModel );

        miqService.sparkleOff();
      });
    }
    $scope.currentTab = "default";
  };

  $scope.changeAuthTab = function(id) {
    $scope.currentTab = id;
  }

  $scope.canValidateBasicInfo = function () {
    return $scope.isBasicInfoValid()
  }

  $scope.isBasicInfoValid = function() {
    if(($scope.currentTab == "default" && $scope.emsCommonModel.emstype != "azure") &&
      ($scope.emsCommonModel.emstype == "ec2" ||
      ($scope.emsCommonModel.emstype == "openstack" && $scope.emsCommonModel.default_hostname ||
       $scope.emsCommonModel.emstype == "scvmm" && $scope.emsCommonModel.default_hostname ||
       $scope.emsCommonModel.emstype == "openstack_infra" && $scope.emsCommonModel.default_hostname ||
       $scope.emsCommonModel.emstype == "rhevm" && $scope.emsCommonModel.default_hostname ||
       $scope.emsCommonModel.emstype == "vmwarews" && $scope.emsCommonModel.default_hostname)) &&
      ($scope.emsCommonModel.default_userid != '' && $scope.angularForm.default_userid.$valid &&
       $scope.emsCommonModel.default_password != '' && $scope.angularForm.default_password.$valid &&
       $scope.emsCommonModel.default_verify != '' && $scope.angularForm.default_verify.$valid)) {
      return true;
    } else if(($scope.currentTab == "amqp") &&
      ($scope.emsCommonModel.amqp_hostname) &&
      ($scope.emsCommonModel.amqp_userid != '' && $scope.angularForm.amqp_userid.$valid &&
       $scope.emsCommonModel.amqp_password != '' && $scope.angularForm.amqp_password.$valid &&
       $scope.emsCommonModel.amqp_verify != '' && $scope.angularForm.amqp_verify.$valid)) {
      return true;
    } else if(($scope.currentTab == "default" && $scope.emsCommonModel.emstype == "azure") &&
      ($scope.emsCommonModel.azure_tenant_id != '' && $scope.angularForm.azure_tenant_id.$valid) &&
      ($scope.emsCommonModel.default_userid != '' && $scope.angularForm.default_userid.$valid &&
       $scope.emsCommonModel.default_password != '' && $scope.angularForm.default_password.$valid &&
       $scope.emsCommonModel.default_verify != '' && $scope.angularForm.default_verify.$valid)) {
      return true;
    } else if(($scope.currentTab == "ssh_keypair" && $scope.emsCommonModel.emstype == "openstack_infra") &&
      ($scope.emsCommonModel.ssh_keypair_userid != '' && $scope.angularForm.ssh_keypair_userid.$valid &&
      $scope.emsCommonModel.ssh_keypair_password != '' && $scope.angularForm.ssh_keypair_password.$valid &&
      $scope.emsCommonModel.ssh_keypair_verify != '' && $scope.angularForm.ssh_keypair_verify.$valid)) {
      return true;
    } else if(($scope.currentTab == "metrics" && $scope.emsCommonModel.emstype == "rhevm") &&
      ($scope.emsCommonModel.metrics_hostname != '' && $scope.angularForm.metrics_hostname.$valid && $scope.emsCommonModel.metrics_api_port != '') &&
      ($scope.emsCommonModel.metrics_userid != '' && $scope.angularForm.metrics_userid.$valid &&
      $scope.emsCommonModel.metrics_password != '' && $scope.angularForm.metrics_password.$valid &&
      $scope.emsCommonModel.metrics_verify != '' && $scope.angularForm.metrics_verify.$valid)) {
      return true;
    } else if($scope.emsCommonModel.emstype == "gce" && $scope.emsCommonModel.project != '' &&
      ($scope.currentTab == "default" ||
      ($scope.currentTab == "service_account" && $scope.emsCommonModel.service_account != ''))) {
      return true;
    }

    else
      return false;
  };

  var emsCommonEditButtonClicked = function(buttonName, serializeFields, $event) {
    miqService.sparkleOn();
    var url = $scope.updateUrl + '?button=' + buttonName;
    miqService.restAjaxButton(url, $event.target);
  };

  var emsCommonAddButtonClicked = function(buttonName, serializeFields, $event) {
    miqService.sparkleOn();
    var url = $scope.createUrl + '?button=' + buttonName;
    miqService.restAjaxButton(url, $event.target);
  };

  $scope.cancelClicked = function($event) {
    angular.element('#button_name').val('cancel');
    if($scope.newRecord)
      emsCommonAddButtonClicked('cancel', false, $event);
    else
      emsCommonEditButtonClicked('cancel', false, $event);

    $scope.angularForm.$setPristine(true);
  };

  $scope.resetClicked = function() {
    $scope.$broadcast ('resetClicked');
    $scope.emsCommonModel = angular.copy( $scope.modelCopy );
    $scope.angularForm.$setPristine(true);
    miqService.miqFlash("warn", __("All changes have been reset"));
  };

  $scope.saveClicked = function($event, formSubmit) {
    if(formSubmit) {
      angular.element('#button_name').val('save');
      emsCommonEditButtonClicked('save', true, $event);
      $scope.angularForm.$setPristine(true);
    }
    else {
      $event.preventDefault();
    }
  };

  $scope.addClicked = function($event, formSubmit) {
    if(formSubmit) {
      angular.element('#button_name').val('add');
      emsCommonAddButtonClicked('add', true, $event);
      $scope.angularForm.$setPristine(true);
    }
    else {
      $event.preventDefault();
    }
  };

  $scope.isRegionSupported = function() {
    if ($scope.emsCommonModel.emstype === 'ec2' || $scope.emsCommonModel.emstype === 'azure') {
      return true;
    }

    return false;
  };

  $scope.providerTypeChanged = function() {
    $scope.emsCommonModel.default_api_port = "";
    $scope.emsCommonModel.default_security_protocol = "";
    $scope.note = "";
    if ($scope.emsCommonModel.emstype === 'openstack' || $scope.emsCommonModel.emstype === 'openstack_infra') {
      $scope.emsCommonModel.default_api_port = "5000";
      $scope.emsCommonModel.event_stream_selection = "ceilometer";
    } else if ($scope.emsCommonModel.emstype === 'scvmm' && $scope.emsCommonModel.default_security_protocol === 'kerberos'){
      $scope.note = $scope.realmNote;
    } else if ($scope.emsCommonModel.emstype === 'rhevm'){
      $scope.emsCommonModel.metrics_api_port = "5432";
    }
  };

  $scope.scvmmSecurityProtocolChanged = function() {
    $scope.note = "";
    if ($scope.emsCommonModel.emstype === 'scvmm' && $scope.emsCommonModel.default_security_protocol === 'kerberos'){
      $scope.note = $scope.realmNote;
    }
  };

  init();
}]);
<commit_msg>Add default value for amqp_security_protocol (transferred from ManageIQ/manageiq@b9fe3aa5db61030f58df2e2ec91caef02611dc8d)<commit_after>ManageIQ.angular.app.controller('emsCommonFormController', ['$http', '$scope', '$attrs', 'emsCommonFormId', 'miqService', function($http, $scope, $attrs, emsCommonFormId, miqService) {
  var init = function() {
    $scope.emsCommonModel = {
      name: '',
      emstype: '',
      openstack_infra_providers_exist: false,
      provider_id: '',
      zone: '',
      hostname: '',
      default_hostname: '',
      amqp_hostname: '',
      metrics_hostname: '',
      project: '',
      default_api_port: '',
      amqp_api_port: '',
      metrics_port: '',
      api_version: '',
      default_security_protocol: '',
      realm: '',
      security_protocol: '',
      amqp_security_protocol: '',
      provider_region: '',
      default_userid: '',
      default_password: '',
      default_verify: '',
      amqp_userid: '',
      amqp_password: '',
      amqp_verify: '',
      metrics_userid: '',
      metrics_password: '',
      metrics_verify: '',
      ssh_keypair_userid: '',
      ssh_keypair_password: '',
      ssh_keypair_verify: '',
      service_account: '',
      emstype_vm: false,
      ems_common: true,
      azure_tenant_id: '',
      keystone_v3_domain_id: '',
      subscription: '',
      host_default_vnc_port_start: '',
      host_default_vnc_port_end: '',
      event_stream_selection: '',
      ems_controller: ''
    };
    $scope.realmNote = __("Note: Username must be in the format: name@realm");
    $scope.formId = emsCommonFormId;
    $scope.afterGet = false;
    $scope.validateClicked = miqService.validateWithREST;
    $scope.modelCopy = angular.copy( $scope.emsCommonModel );
    $scope.formFieldsUrl = $attrs.formFieldsUrl;
    $scope.createUrl = $attrs.createUrl;
    $scope.updateUrl = $attrs.updateUrl;
    $scope.model = 'emsCommonModel';

    ManageIQ.angular.scope = $scope;

    if (emsCommonFormId == 'new') {
      $scope.newRecord                  = true;

      miqService.sparkleOn();
      $http.get($scope.formFieldsUrl + emsCommonFormId).success(function(data) {
        $scope.emsCommonModel.zone                            = data.zone;
        $scope.emsCommonModel.emstype_vm                      = data.emstype_vm;
        $scope.emsCommonModel.openstack_infra_providers_exist = data.openstack_infra_providers_exist;
        $scope.emsCommonModel.default_api_port                = 5000;
        $scope.emsCommonModel.amqp_api_port                   = 5672;
        $scope.emsCommonModel.api_version                     = 'v2';
        $scope.emsCommonModel.ems_controller                  = data.ems_controller;
        miqService.sparkleOff();
      });
      $scope.afterGet  = true;
      $scope.modelCopy = angular.copy( $scope.emsCommonModel );
    }
    else {
      $scope.newRecord = false;
      miqService.sparkleOn();

      $http.get($scope.formFieldsUrl + emsCommonFormId).success(function(data) {
        $scope.emsCommonModel.name                            = data.name;
        $scope.emsCommonModel.emstype                         = data.emstype;
        $scope.emsCommonModel.zone                            = data.zone;
        $scope.emsCommonModel.hostname                        = data.hostname;
        $scope.emsCommonModel.default_hostname                = data.default_hostname;
        $scope.emsCommonModel.amqp_hostname                   = data.amqp_hostname;
        $scope.emsCommonModel.metrics_hostname                = data.metrics_hostname;
        $scope.emsCommonModel.project                         = data.project;

        $scope.emsCommonModel.openstack_infra_providers_exist = data.openstack_infra_providers_exist;

        $scope.emsCommonModel.provider_id                     = angular.isDefined(data.provider_id) ? data.provider_id.toString() : "";

        $scope.emsCommonModel.default_api_port                = angular.isDefined(data.default_api_port) && data.default_api_port != '' ? data.default_api_port : '5000';
        $scope.emsCommonModel.amqp_api_port                   = angular.isDefined(data.amqp_api_port) && data.amqp_api_port != '' ? data.amqp_api_port : '5672';
        $scope.emsCommonModel.metrics_api_port                = angular.isDefined(data.metrics_api_port) && data.metrics_api_port != '' ? data.metrics_api_port : '';
        $scope.emsCommonModel.api_version                     = data.api_version;
        $scope.emsCommonModel.default_security_protocol       = data.default_security_protocol;
        $scope.emsCommonModel.realm                           = data.realm;
        $scope.emsCommonModel.security_protocol               = data.security_protocol;
        $scope.emsCommonModel.amqp_security_protocol          = data.amqp_security_protocol != '' ? data.amqp_security_protocol : 'ssl';
        $scope.emsCommonModel.provider_region                 = data.provider_region;
        $scope.emsCommonModel.default_userid                  = data.default_userid;
        $scope.emsCommonModel.amqp_userid                     = data.amqp_userid;
        $scope.emsCommonModel.metrics_userid                  = data.metrics_userid;

        $scope.emsCommonModel.ssh_keypair_userid              = data.ssh_keypair_userid;

        $scope.emsCommonModel.service_account                 = data.service_account;
        $scope.emsCommonModel.azure_tenant_id                 = data.azure_tenant_id;
        $scope.emsCommonModel.keystone_v3_domain_id           = data.keystone_v3_domain_id;
        $scope.emsCommonModel.subscription                    = data.subscription;

        $scope.emsCommonModel.host_default_vnc_port_start     = data.host_default_vnc_port_start;
        $scope.emsCommonModel.host_default_vnc_port_end       = data.host_default_vnc_port_end;

        $scope.emsCommonModel.ems_controller                  = data.ems_controller;

        if($scope.emsCommonModel.default_userid != '') {
          $scope.emsCommonModel.default_password = $scope.emsCommonModel.default_verify = miqService.storedPasswordPlaceholder;
        }
        if($scope.emsCommonModel.amqp_userid != '') {
          $scope.emsCommonModel.amqp_password = $scope.emsCommonModel.amqp_verify = miqService.storedPasswordPlaceholder;
        }
        if($scope.emsCommonModel.metrics_userid != '') {
          $scope.emsCommonModel.metrics_password = $scope.emsCommonModel.metrics_verify = miqService.storedPasswordPlaceholder;
        }
        if($scope.emsCommonModel.ssh_keypair_userid != '') {
          $scope.emsCommonModel.ssh_keypair_password = $scope.emsCommonModel.ssh_keypair_verify = miqService.storedPasswordPlaceholder;
        }

        $scope.afterGet  = true;
        $scope.modelCopy = angular.copy( $scope.emsCommonModel );

        miqService.sparkleOff();
      });
    }
    $scope.currentTab = "default";
  };

  $scope.changeAuthTab = function(id) {
    $scope.currentTab = id;
  }

  $scope.canValidateBasicInfo = function () {
    return $scope.isBasicInfoValid()
  }

  $scope.isBasicInfoValid = function() {
    if(($scope.currentTab == "default" && $scope.emsCommonModel.emstype != "azure") &&
      ($scope.emsCommonModel.emstype == "ec2" ||
      ($scope.emsCommonModel.emstype == "openstack" && $scope.emsCommonModel.default_hostname ||
       $scope.emsCommonModel.emstype == "scvmm" && $scope.emsCommonModel.default_hostname ||
       $scope.emsCommonModel.emstype == "openstack_infra" && $scope.emsCommonModel.default_hostname ||
       $scope.emsCommonModel.emstype == "rhevm" && $scope.emsCommonModel.default_hostname ||
       $scope.emsCommonModel.emstype == "vmwarews" && $scope.emsCommonModel.default_hostname)) &&
      ($scope.emsCommonModel.default_userid != '' && $scope.angularForm.default_userid.$valid &&
       $scope.emsCommonModel.default_password != '' && $scope.angularForm.default_password.$valid &&
       $scope.emsCommonModel.default_verify != '' && $scope.angularForm.default_verify.$valid)) {
      return true;
    } else if(($scope.currentTab == "amqp") &&
      ($scope.emsCommonModel.amqp_hostname) &&
      ($scope.emsCommonModel.amqp_userid != '' && $scope.angularForm.amqp_userid.$valid &&
       $scope.emsCommonModel.amqp_password != '' && $scope.angularForm.amqp_password.$valid &&
       $scope.emsCommonModel.amqp_verify != '' && $scope.angularForm.amqp_verify.$valid)) {
      return true;
    } else if(($scope.currentTab == "default" && $scope.emsCommonModel.emstype == "azure") &&
      ($scope.emsCommonModel.azure_tenant_id != '' && $scope.angularForm.azure_tenant_id.$valid) &&
      ($scope.emsCommonModel.default_userid != '' && $scope.angularForm.default_userid.$valid &&
       $scope.emsCommonModel.default_password != '' && $scope.angularForm.default_password.$valid &&
       $scope.emsCommonModel.default_verify != '' && $scope.angularForm.default_verify.$valid)) {
      return true;
    } else if(($scope.currentTab == "ssh_keypair" && $scope.emsCommonModel.emstype == "openstack_infra") &&
      ($scope.emsCommonModel.ssh_keypair_userid != '' && $scope.angularForm.ssh_keypair_userid.$valid &&
      $scope.emsCommonModel.ssh_keypair_password != '' && $scope.angularForm.ssh_keypair_password.$valid &&
      $scope.emsCommonModel.ssh_keypair_verify != '' && $scope.angularForm.ssh_keypair_verify.$valid)) {
      return true;
    } else if(($scope.currentTab == "metrics" && $scope.emsCommonModel.emstype == "rhevm") &&
      ($scope.emsCommonModel.metrics_hostname != '' && $scope.angularForm.metrics_hostname.$valid && $scope.emsCommonModel.metrics_api_port != '') &&
      ($scope.emsCommonModel.metrics_userid != '' && $scope.angularForm.metrics_userid.$valid &&
      $scope.emsCommonModel.metrics_password != '' && $scope.angularForm.metrics_password.$valid &&
      $scope.emsCommonModel.metrics_verify != '' && $scope.angularForm.metrics_verify.$valid)) {
      return true;
    } else if($scope.emsCommonModel.emstype == "gce" && $scope.emsCommonModel.project != '' &&
      ($scope.currentTab == "default" ||
      ($scope.currentTab == "service_account" && $scope.emsCommonModel.service_account != ''))) {
      return true;
    }

    else
      return false;
  };

  var emsCommonEditButtonClicked = function(buttonName, serializeFields, $event) {
    miqService.sparkleOn();
    var url = $scope.updateUrl + '?button=' + buttonName;
    miqService.restAjaxButton(url, $event.target);
  };

  var emsCommonAddButtonClicked = function(buttonName, serializeFields, $event) {
    miqService.sparkleOn();
    var url = $scope.createUrl + '?button=' + buttonName;
    miqService.restAjaxButton(url, $event.target);
  };

  $scope.cancelClicked = function($event) {
    angular.element('#button_name').val('cancel');
    if($scope.newRecord)
      emsCommonAddButtonClicked('cancel', false, $event);
    else
      emsCommonEditButtonClicked('cancel', false, $event);

    $scope.angularForm.$setPristine(true);
  };

  $scope.resetClicked = function() {
    $scope.$broadcast ('resetClicked');
    $scope.emsCommonModel = angular.copy( $scope.modelCopy );
    $scope.angularForm.$setPristine(true);
    miqService.miqFlash("warn", __("All changes have been reset"));
  };

  $scope.saveClicked = function($event, formSubmit) {
    if(formSubmit) {
      angular.element('#button_name').val('save');
      emsCommonEditButtonClicked('save', true, $event);
      $scope.angularForm.$setPristine(true);
    }
    else {
      $event.preventDefault();
    }
  };

  $scope.addClicked = function($event, formSubmit) {
    if(formSubmit) {
      angular.element('#button_name').val('add');
      emsCommonAddButtonClicked('add', true, $event);
      $scope.angularForm.$setPristine(true);
    }
    else {
      $event.preventDefault();
    }
  };

  $scope.isRegionSupported = function() {
    if ($scope.emsCommonModel.emstype === 'ec2' || $scope.emsCommonModel.emstype === 'azure') {
      return true;
    }

    return false;
  };

  $scope.providerTypeChanged = function() {
    $scope.emsCommonModel.default_api_port = "";
    $scope.emsCommonModel.default_security_protocol = "";
    $scope.note = "";
    if ($scope.emsCommonModel.emstype === 'openstack' || $scope.emsCommonModel.emstype === 'openstack_infra') {
      $scope.emsCommonModel.default_api_port = "5000";
      $scope.emsCommonModel.event_stream_selection = "ceilometer";
      $scope.emsCommonModel.amqp_security_protocol = 'ssl';
    } else if ($scope.emsCommonModel.emstype === 'scvmm' && $scope.emsCommonModel.default_security_protocol === 'kerberos'){
      $scope.note = $scope.realmNote;
    } else if ($scope.emsCommonModel.emstype === 'rhevm'){
      $scope.emsCommonModel.metrics_api_port = "5432";
    }
  };

  $scope.scvmmSecurityProtocolChanged = function() {
    $scope.note = "";
    if ($scope.emsCommonModel.emstype === 'scvmm' && $scope.emsCommonModel.default_security_protocol === 'kerberos'){
      $scope.note = $scope.realmNote;
    }
  };

  init();
}]);
<|endoftext|>


<commit_before>import Alt from '../Alt';

class ListActions {
  updateItems(items) {
    this.dispatch(items);
  }

  addItem(item) {
    this.dispatch(item)
  }
}

export default Alt.createActions(ListActions);
<commit_msg>Adds action to remove item from list.<commit_after>import Alt from '../Alt';

class ListActions {
  updateItems(items) {
    this.dispatch(items);
  }

  addItem(item) {
    this.dispatch(item)
  }

  removeItem(index) {
    this.dispatch(index)
  }
}

export default Alt.createActions(ListActions);
<|endoftext|>


<commit_before>'use strict';

angular.module('deckApp.gce.serverGroupCommandBuilder.service', [
  'restangular',
  'deckApp.settings',
  'deckApp.account.service',
  'deckApp.naming',
  'deckApp.gce.instanceType.service',
])
  .factory('gceServerGroupCommandBuilder', function (settings, Restangular, $exceptionHandler, $q, accountService, gceInstanceTypeService, namingService) {

    // Two assumptions here:
    //   1) All GCE machine types are represented in the tree of choices.
    //   2) Each machine type appears in exactly one category.
    function determineInstanceCategoryFromInstanceType(command) {
      gceInstanceTypeService.getCategories().then(function(categories) {
        categories.forEach(function(category) {
          category.families.forEach(function(family) {
            family.instanceTypes.forEach(function(instanceType) {
              if (instanceType.name === command.instanceType) {
                command.viewState.instanceProfile = category.type;
              }
            });
          });
        });
      });
    }

    function populateCustomMetadata(userData, command) {
      if (userData) {
        // userData is a base64-encoded json object.
        var userDataObj = JSON.parse(window.atob(userData));

        for (var key in userDataObj) {
          // Don't show 'load-balancer-names' key/value pair in the wizard.
          if (key !== 'load-balancer-names') {
            // The 'key' and 'value' attributes are used to enable the Add/Remove behavior in the wizard.
            command.instanceMetadata.push({key: key, value: userDataObj[key]});
          }
        }
      }
    }

    function buildNewServerGroupCommand(application) {

    return {
      application: application.name,
      credentials: 'my-account-name',
      region: 'us-central1',
      capacity: {
        min: 0,
        max: 0,
        desired: 1
      },
      instanceMetadata: [],
      cooldown: 10,
      healthCheckType: 'EC2',
      healthCheckGracePeriod: 600,
      instanceMonitoring: false,
      ebsOptimized: false,
      providerType: 'gce',
      selectedProvider: 'gce',
      iamRole: 'BaseIAMRole',       // should not be hard coded here

      terminationPolicies: ['Default'],
      vpcId: null,
      availabilityZones: [],
      keyPair: 'nf-test-keypair-a', // should not be hard coded here
      viewState: {
        instanceProfile: null,
        allImageSelection: null,
        useAllImageSelection: false,
        useSimpleCapacity: true,
        usePreferredZones: true,
        mode: 'create',
      },
    };
  }

    function buildServerGroupCommandFromExisting(application, serverGroup, mode) {
      mode = mode || 'clone';

      var serverGroupName = namingService.parseServerGroupName(serverGroup.name);

      var command = {
        application: application.name,
        stack: serverGroupName.stack,
        freeFormDetails: serverGroupName.freeFormDetails,
        credentials: serverGroup.account,
        cooldown: serverGroup.asg.defaultCooldown,
        healthCheckGracePeriod: serverGroup.asg.healthCheckGracePeriod,
        healthCheckType: serverGroup.asg.healthCheckType,
        terminationPolicies: serverGroup.asg.terminationPolicies,
        loadBalancers: serverGroup.asg.loadBalancerNames,
        region: serverGroup.region,
        capacity: {
          min: serverGroup.asg.minSize,
          max: serverGroup.asg.maxSize,
          desired: serverGroup.asg.desiredCapacity
        },
        zone: serverGroup.zones[0],
        instanceMetadata: [],
        availabilityZones: serverGroup.asg.availabilityZones,
        providerType: 'gce',
        selectedProvider: 'gce',
        source: {
          account: serverGroup.account,
          region: serverGroup.region,
          zone: serverGroup.zones[0],
          serverGroupName: serverGroup.name,
          asgName: serverGroup.name
        },
        viewState: {
          allImageSelection: null,
          useAllImageSelection: false,
          useSimpleCapacity: serverGroup.asg.minSize === serverGroup.asg.maxSize,
          usePreferredZones: false,
          mode: mode,
        },
      };

      if (serverGroup.launchConfig) {
        angular.extend(command, {
          instanceType: serverGroup.launchConfig.instanceType,
          iamRole: serverGroup.launchConfig.iamInstanceProfile,
          keyPair: serverGroup.launchConfig.keyName,
          associatePublicIpAddress: serverGroup.launchConfig.associatePublicIpAddress,
          ramdiskId: serverGroup.launchConfig.ramdiskId,
          instanceMonitoring: serverGroup.launchConfig.instanceMonitoring && serverGroup.launchConfig.instanceMonitoring.enabled,
          ebsOptimized: serverGroup.launchConfig.ebsOptimized,
        });
        command.viewState.imageId = serverGroup.launchConfig.imageId;
        determineInstanceCategoryFromInstanceType(command);
        populateCustomMetadata(serverGroup.launchConfig.userData, command);
      }

      return command;
    }

    function buildSubmittableCommand(original) {
      var command = angular.copy(original);
      var transformedInstanceMetadata = {};
      // The instanceMetadata is stored using 'key' and 'value' attributes to enable the Add/Remove behavior in the wizard.
      command.instanceMetadata.forEach(function(metadataPair) {
        transformedInstanceMetadata[metadataPair.key] = metadataPair.value;
      });

      // We use this list of load balancer names when 'Enabling' a server group.
      if (command.loadBalancers.length > 0) {
        transformedInstanceMetadata['load-balancer-names'] = command.loadBalancers.toString();
      }
      command.instanceMetadata = transformedInstanceMetadata;
      return command;
    }

    return {
      buildNewServerGroupCommand: buildNewServerGroupCommand,
      buildServerGroupCommandFromExisting: buildServerGroupCommandFromExisting,
      buildSubmittableCommand: buildSubmittableCommand
    };
});

<commit_msg>Address 'undefined' loadBalancers on clone of server group with 0 load balancers. Use first defined account as default.<commit_after>'use strict';

angular.module('deckApp.gce.serverGroupCommandBuilder.service', [
  'restangular',
  'deckApp.settings',
  'deckApp.account.service',
  'deckApp.naming',
  'deckApp.gce.instanceType.service',
])
  .factory('gceServerGroupCommandBuilder', function (settings, Restangular, $exceptionHandler, $q, accountService, gceInstanceTypeService, namingService) {

    // Two assumptions here:
    //   1) All GCE machine types are represented in the tree of choices.
    //   2) Each machine type appears in exactly one category.
    function determineInstanceCategoryFromInstanceType(command) {
      gceInstanceTypeService.getCategories().then(function(categories) {
        categories.forEach(function(category) {
          category.families.forEach(function(family) {
            family.instanceTypes.forEach(function(instanceType) {
              if (instanceType.name === command.instanceType) {
                command.viewState.instanceProfile = category.type;
              }
            });
          });
        });
      });
    }

    function populateCustomMetadata(userData, command) {
      if (userData) {
        // userData is a base64-encoded json object.
        var userDataObj = JSON.parse(window.atob(userData));

        for (var key in userDataObj) {
          // Don't show 'load-balancer-names' key/value pair in the wizard.
          if (key !== 'load-balancer-names') {
            // The 'key' and 'value' attributes are used to enable the Add/Remove behavior in the wizard.
            command.instanceMetadata.push({key: key, value: userDataObj[key]});
          }
        }
      }
    }

    function buildNewServerGroupCommand(application) {

    // TODO(duftler): Fetch default account from settings once it's refactored to support defaults for multiple providers.
    return {
      application: application.name,
      credentials: application.accounts.length > 0 ? application.accounts[0] : 'my-account-name',
      region: 'us-central1',
      capacity: {
        min: 0,
        max: 0,
        desired: 1
      },
      instanceMetadata: [],
      cooldown: 10,
      healthCheckType: 'EC2',
      healthCheckGracePeriod: 600,
      instanceMonitoring: false,
      ebsOptimized: false,
      providerType: 'gce',
      selectedProvider: 'gce',
      iamRole: 'BaseIAMRole',       // should not be hard coded here

      terminationPolicies: ['Default'],
      vpcId: null,
      availabilityZones: [],
      keyPair: 'nf-test-keypair-a', // should not be hard coded here
      viewState: {
        instanceProfile: null,
        allImageSelection: null,
        useAllImageSelection: false,
        useSimpleCapacity: true,
        usePreferredZones: true,
        mode: 'create',
      },
    };
  }

    function buildServerGroupCommandFromExisting(application, serverGroup, mode) {
      mode = mode || 'clone';

      var serverGroupName = namingService.parseServerGroupName(serverGroup.name);

      var command = {
        application: application.name,
        stack: serverGroupName.stack,
        freeFormDetails: serverGroupName.freeFormDetails,
        credentials: serverGroup.account,
        cooldown: serverGroup.asg.defaultCooldown,
        healthCheckGracePeriod: serverGroup.asg.healthCheckGracePeriod,
        healthCheckType: serverGroup.asg.healthCheckType,
        terminationPolicies: serverGroup.asg.terminationPolicies,
        loadBalancers: serverGroup.asg.loadBalancerNames,
        region: serverGroup.region,
        capacity: {
          min: serverGroup.asg.minSize,
          max: serverGroup.asg.maxSize,
          desired: serverGroup.asg.desiredCapacity
        },
        zone: serverGroup.zones[0],
        instanceMetadata: [],
        availabilityZones: serverGroup.asg.availabilityZones,
        providerType: 'gce',
        selectedProvider: 'gce',
        source: {
          account: serverGroup.account,
          region: serverGroup.region,
          zone: serverGroup.zones[0],
          serverGroupName: serverGroup.name,
          asgName: serverGroup.name
        },
        viewState: {
          allImageSelection: null,
          useAllImageSelection: false,
          useSimpleCapacity: serverGroup.asg.minSize === serverGroup.asg.maxSize,
          usePreferredZones: false,
          mode: mode,
        },
      };

      if (serverGroup.launchConfig) {
        angular.extend(command, {
          instanceType: serverGroup.launchConfig.instanceType,
          iamRole: serverGroup.launchConfig.iamInstanceProfile,
          keyPair: serverGroup.launchConfig.keyName,
          associatePublicIpAddress: serverGroup.launchConfig.associatePublicIpAddress,
          ramdiskId: serverGroup.launchConfig.ramdiskId,
          instanceMonitoring: serverGroup.launchConfig.instanceMonitoring && serverGroup.launchConfig.instanceMonitoring.enabled,
          ebsOptimized: serverGroup.launchConfig.ebsOptimized,
        });
        command.viewState.imageId = serverGroup.launchConfig.imageId;
        determineInstanceCategoryFromInstanceType(command);
        populateCustomMetadata(serverGroup.launchConfig.userData, command);
      }

      return command;
    }

    function buildSubmittableCommand(original) {
      var command = angular.copy(original);
      var transformedInstanceMetadata = {};
      // The instanceMetadata is stored using 'key' and 'value' attributes to enable the Add/Remove behavior in the wizard.
      command.instanceMetadata.forEach(function(metadataPair) {
        transformedInstanceMetadata[metadataPair.key] = metadataPair.value;
      });

      // We use this list of load balancer names when 'Enabling' a server group.
      if (command.loadBalancers && command.loadBalancers.length > 0) {
        transformedInstanceMetadata['load-balancer-names'] = command.loadBalancers.toString();
      }
      command.instanceMetadata = transformedInstanceMetadata;
      return command;
    }

    return {
      buildNewServerGroupCommand: buildNewServerGroupCommand,
      buildServerGroupCommandFromExisting: buildServerGroupCommandFromExisting,
      buildSubmittableCommand: buildSubmittableCommand
    };
});

<|endoftext|>


<commit_before>/*globals requireJS*/
/*jshint node:true*/
/**
 * @author pmeijer / https://github.com/pmeijer
 */
'use strict';

var Q = require('q'),
    BlobClient = requireJS('common/blob/BlobClient'),
    Core = requireJS('common/core/core');

/**
 * Monitors given branch and starts, stops and updates registered addOns.
 *
 *
 * @param {string} webGMESessionId
 * @param {EditorStorage} storage
 * @param {Project} project
 * @param {string} branchName
 * @param {object} gmeConfig
 * @param {object} mainLogger
 * @constructor
 */
function BranchMonitor(webGMESessionId, storage, project, branchName, mainLogger, gmeConfig) {
    var self = this,
        logger = mainLogger.fork('BranchMonitor:' + branchName),
        core = new Core(project, {globConf: gmeConfig, logger: logger.fork('core')}),
        startDeferred,
        stopDeferred;

    this.runningAddOns = [
        //{id: {string}, instance: {AddOnBase}}
    ];

    // State
    this.commitHash = '';
    this.rootHash = '';
    this.rootNode = null;
    this.commitMessage = '';

    this.stopRequested = false;
    this.startRequested = false;
    this.branchIsOpen = false;

    // Helper functions
    function getAddOn(id) {
        var addOnPath = 'addon/' + id + '/' + id + '/' + id,
            AddOn,
            error,
            addOn;

        logger.debug('requireJS addOn from path: ' + addOnPath);
        try {
            AddOn = requireJS(addOnPath);
        } catch (err) {
            error = err;
        }

        // This is weird, the second time requirejs simply returns with undefined.
        if (AddOn) {
            addOn = new AddOn(logger.fork(id), gmeConfig);
            return addOn;
        } else {
            return error || new Error('AddOn is not available from: ' + addOnPath);
        }
    }

    function getConfiguration() {
        var blobClient = new BlobClient({
            serverPort: gmeConfig.server.port,
            httpsecure: gmeConfig.server.https.enable,
            server: '127.0.0.1',
            webgmeclientsession: webGMESessionId
        });

        return {
            core: core,
            project: project,
            branchName: branchName,
            blobClient: blobClient
        };
    }

    function loadNewRoot(commitData, callback) {
        var deferred = Q.defer();
        self.rootHash = commitData.commitObject.root;
        self.commitHash = commitData.commitObject._id;
        logger.debug('loadNewRoot [commit/rootHash]', self.commitHash, self.rootHash);

        core.loadRoot(self.rootHash, function (err, root) {
            if (err) {
                deferred.reject(new Error(err));
                return;
            }

            self.rootNode = root;
            deferred.resolve(root);
        });

        return deferred.promise.nodeify(callback);
    }

    function updateRunningAddOns(commitObj, callback) {
        var deferred = new Q.defer(),
            counter = 0,
            limit = self.runningAddOns.length;

        function getUpdateCallback(addOn, counter) {
            return function (err, data) {
                if (err) {
                    // TODO: How to handle this?
                    logger.error('AddOn [' + addOn.id + '] returned error at init/update', err);
                }

                if (data.commitMessage) {
                    self.commitMessage += ' - [' + addOn.instance.getName() + '] (v' + addOn.instance.getVersion() +
                        ') ' + data.commitMessage;
                    logger.debug('AddOn [' + addOn.id + '] added to commitMessage', self.commitMessage);
                }

                if (data.notification) {
                    logger.warn('AddOn [' + addOn.id + '] sent not yet supported notification!', data.notification);
                }

                updateAddOn(self.runningAddOns[counter]);
            };
        }

        function updateAddOn(addOn) {
            if (counter === limit) {
                deferred.resolve();
                return;
            }
            counter += 1;
            if (addOn.instance.initialized === true) {
                logger.debug('updating addOn: ', addOn.id);
                addOn.instance.update(self.rootNode, commitObj, getUpdateCallback(addOn, counter));
            } else {
                addOn.instance.configure(getConfiguration());
                logger.debug('initializing addOn: ', addOn.id);
                addOn.instance._initialize(self.rootNode, commitObj, getUpdateCallback(addOn, counter));
            }
        }

        if (limit === 0) {
            logger.debug('There are no running addOns');
            deferred.resolve();
        } else {
            updateAddOn(self.runningAddOns[0]);
        }

        return deferred.promise.nodeify(callback);
    }

    function onUpdate(eventData, commitQueue, updateQueue, handlerCallback) {
        var commitData = eventData.commitData;

        if (eventData.local) {
            // This is when an addOn made changes and a commit was made below.
            logger.debug('AddOn made changes (local event data)');
            handlerCallback(null, self.stopRequested === false);
            return;
        }

        // loadNewRoot will set self.commitHash/rootHash/rootNode
        loadNewRoot(commitData)
            .then(function () {
                var runningAddOnsNew = [],
                    requiredAddOns = core.getRegistry(self.rootNode, 'usedAddOns'),
                    i,
                    j,
                    newAddOn,
                    wasRunning;

                if (typeof requiredAddOns === 'string') {
                    requiredAddOns = requiredAddOns.trim();
                    requiredAddOns = requiredAddOns ? requiredAddOns.split(' ') : [];
                } else {
                    requiredAddOns = [];
                }

                logger.debug('requiredAddOns:', requiredAddOns);

                for (i = 0; i < requiredAddOns.length; i += 1) {
                    wasRunning = false;
                    for (j = 0; self.runningAddOns.length; j += 1) {
                        if (self.runningAddOns[j].id === requiredAddOns[i]) {
                            runningAddOnsNew.push(self.runningAddOns[j]);
                            wasRunning = true;
                            break;
                        }
                    }
                    if (wasRunning === false) {
                        newAddOn = getAddOn(requiredAddOns[i]);
                        if (newAddOn instanceof Error) {
                            logger.error('Could not get addOn', newAddOn);
                        } else {
                            runningAddOnsNew.push({
                                id: requiredAddOns[i],
                                instance: newAddOn
                            });
                        }
                    }
                }

                self.runningAddOns = runningAddOnsNew;
                self.commitMessage = 'AddOns';

                return updateRunningAddOns(commitData.commitObject);
            })
            .then(function () {
                var persisted = core.persist(self.rootNode),
                    persistedObjects = Object.keys(persisted.objects);
                if (persistedObjects.length === 0) {
                    logger.debug('No changes made by addOns');
                } else {
                    // This will create an update event with local:true, see top of function.
                    logger.debug('Changes were made', self.commitMessage);
                    logger.debug('Number of persisted objects', persistedObjects.length);
                    project.makeCommit(branchName, [self.commitHash], persisted.rootHash,
                        persisted.objects, self.commitMessage,
                        function (err, result) {
                            if (err) {
                                logger.error('makeCommit', err);
                            } else {
                                logger.debug('makeCommit', result);
                            }
                        });
                }
                handlerCallback(null, self.stopRequested === false);
            })
            .catch(function (err) {
                logger.error('Fatal error', err);
                handlerCallback(err, false);
            });
    }

    function branchStatusHandler(branchStatus /*, commitQueue, updateQueue*/) {
        //TODO check how it should work
        logger.debug('New branchStatus', branchStatus);
    }

    // API functions
    this.start = function (callback) {
        if (self.startRequested === false) {
            startDeferred = Q.defer();
            self.startRequested = true;

            storage.openBranch(project.projectId, branchName, onUpdate, branchStatusHandler,
                function (err/*, latestCommitData*/) {
                    if (err) {
                        startDeferred.reject(err);
                        return;
                    }
                    self.branchIsOpen = true;
                    startDeferred.resolve();
                }
            );
        }

        return startDeferred.promise.nodeify(callback);
    };

    this.stop = function (callback) {
        if (self.stopRequested === false) {
            stopDeferred = Q.defer();
            self.stopRequested = true;

            storage.closeBranch(project.projectId, branchName, function (err) {
                self.branchIsOpen = false;
                if (err) {
                    stopDeferred.reject(err);
                } else {
                    stopDeferred.resolve();
                }
            });
        }

        return stopDeferred.promise.nodeify(callback);
    };

    this.queryAddOn = function (addOnId, commitHash, queryParams, callback) {
        var deferred = Q.defer();
        deferred.reject(new Error('queryAddOn not implemented yet!'));
        return deferred.promise.nodeify(callback);
    };
}

module.exports = BranchMonitor;<commit_msg>#579 Add comment for reminder.<commit_after>/*globals requireJS*/
/*jshint node:true*/
/**
 * @author pmeijer / https://github.com/pmeijer
 */
'use strict';

var Q = require('q'),
    BlobClient = requireJS('common/blob/BlobClient'),
    Core = requireJS('common/core/core');

/**
 * Monitors given branch and starts, stops and updates registered addOns.
 *
 *
 * @param {string} webGMESessionId
 * @param {EditorStorage} storage
 * @param {Project} project
 * @param {string} branchName
 * @param {object} gmeConfig
 * @param {object} mainLogger
 * @constructor
 */
function BranchMonitor(webGMESessionId, storage, project, branchName, mainLogger, gmeConfig) {
    var self = this,
        logger = mainLogger.fork('BranchMonitor:' + branchName),
        core = new Core(project, {globConf: gmeConfig, logger: logger.fork('core')}),
        startDeferred,
        stopDeferred;

    this.runningAddOns = [
        //{id: {string}, instance: {AddOnBase}}
    ];

    // State
    this.commitHash = '';
    this.rootHash = '';
    this.rootNode = null;
    this.commitMessage = '';

    this.stopRequested = false;
    this.startRequested = false;
    this.branchIsOpen = false;

    // Helper functions
    function getAddOn(id) {
        var addOnPath = 'addon/' + id + '/' + id + '/' + id,
            AddOn,
            error,
            addOn;

        logger.debug('requireJS addOn from path: ' + addOnPath);
        try {
            AddOn = requireJS(addOnPath);
        } catch (err) {
            error = err;
        }

        // This is weird, the second time requirejs simply returns with undefined.
        if (AddOn) {
            addOn = new AddOn(logger.fork(id), gmeConfig);
            return addOn;
        } else {
            return error || new Error('AddOn is not available from: ' + addOnPath);
        }
    }

    function getConfiguration() {
        var blobClient = new BlobClient({
            serverPort: gmeConfig.server.port,
            httpsecure: gmeConfig.server.https.enable,
            server: '127.0.0.1',
            webgmeclientsession: webGMESessionId
        });

        return {
            core: core,
            project: project,
            branchName: branchName,
            blobClient: blobClient
        };
    }

    function loadNewRoot(commitData, callback) {
        var deferred = Q.defer();
        self.rootHash = commitData.commitObject.root;
        self.commitHash = commitData.commitObject._id;
        logger.debug('loadNewRoot [commit/rootHash]', self.commitHash, self.rootHash);

        core.loadRoot(self.rootHash, function (err, root) {
            if (err) {
                deferred.reject(new Error(err));
                return;
            }

            self.rootNode = root;
            deferred.resolve(root);
        });

        return deferred.promise.nodeify(callback);
    }

    function updateRunningAddOns(commitObj, callback) {
        var deferred = new Q.defer(),
            counter = 0,
            limit = self.runningAddOns.length;

        function getUpdateCallback(addOn, counter) {
            return function (err, data) {
                if (err) {
                    // TODO: How to handle this?
                    logger.error('AddOn [' + addOn.id + '] returned error at init/update', err);
                }

                if (data.commitMessage) {
                    self.commitMessage += ' - [' + addOn.instance.getName() + '] (v' + addOn.instance.getVersion() +
                        ') ' + data.commitMessage;
                    logger.debug('AddOn [' + addOn.id + '] added to commitMessage', self.commitMessage);
                }

                if (data.notification) {
                    logger.warn('AddOn [' + addOn.id + '] sent not yet supported notification!', data.notification);
                }

                updateAddOn(self.runningAddOns[counter]);
            };
        }

        function updateAddOn(addOn) {
            if (counter === limit) {
                deferred.resolve();
                return;
            }
            counter += 1;
            if (addOn.instance.initialized === true) {
                logger.debug('updating addOn: ', addOn.id);
                addOn.instance.update(self.rootNode, commitObj, getUpdateCallback(addOn, counter));
            } else {
                addOn.instance.configure(getConfiguration());
                logger.debug('initializing addOn: ', addOn.id);
                addOn.instance._initialize(self.rootNode, commitObj, getUpdateCallback(addOn, counter));
            }
        }

        if (limit === 0) {
            logger.debug('There are no running addOns');
            deferred.resolve();
        } else {
            updateAddOn(self.runningAddOns[0]);
        }

        return deferred.promise.nodeify(callback);
    }

    function onUpdate(eventData, commitQueue, updateQueue, handlerCallback) {
        var commitData = eventData.commitData;

        if (eventData.local) {
            // This is when an addOn made changes and a commit was made below.
            logger.debug('AddOn made changes (local event data)');
            handlerCallback(null, self.stopRequested === false);
            return;
        }

        // loadNewRoot will set self.commitHash/rootHash/rootNode
        loadNewRoot(commitData)
            .then(function () {
                var runningAddOnsNew = [],
                    requiredAddOns = core.getRegistry(self.rootNode, 'usedAddOns'),
                    i,
                    j,
                    newAddOn,
                    wasRunning;

                if (typeof requiredAddOns === 'string') {
                    requiredAddOns = requiredAddOns.trim();
                    requiredAddOns = requiredAddOns ? requiredAddOns.split(' ') : [];
                } else {
                    requiredAddOns = [];
                }

                logger.debug('requiredAddOns:', requiredAddOns);

                for (i = 0; i < requiredAddOns.length; i += 1) {
                    wasRunning = false;
                    for (j = 0; self.runningAddOns.length; j += 1) {
                        //FIXME: This can raise an error that
                        if (self.runningAddOns[j].id === requiredAddOns[i]) {
                            runningAddOnsNew.push(self.runningAddOns[j]);
                            wasRunning = true;
                            break;
                        }
                    }
                    if (wasRunning === false) {
                        newAddOn = getAddOn(requiredAddOns[i]);
                        if (newAddOn instanceof Error) {
                            logger.error('Could not get addOn', newAddOn);
                        } else {
                            runningAddOnsNew.push({
                                id: requiredAddOns[i],
                                instance: newAddOn
                            });
                        }
                    }
                }

                self.runningAddOns = runningAddOnsNew;
                self.commitMessage = 'AddOns';

                return updateRunningAddOns(commitData.commitObject);
            })
            .then(function () {
                var persisted = core.persist(self.rootNode),
                    persistedObjects = Object.keys(persisted.objects);
                if (persistedObjects.length === 0) {
                    logger.debug('No changes made by addOns');
                } else {
                    // This will create an update event with local:true, see top of function.
                    logger.debug('Changes were made', self.commitMessage);
                    logger.debug('Number of persisted objects', persistedObjects.length);
                    project.makeCommit(branchName, [self.commitHash], persisted.rootHash,
                        persisted.objects, self.commitMessage,
                        function (err, result) {
                            if (err) {
                                logger.error('makeCommit', err);
                            } else {
                                logger.debug('makeCommit', result);
                            }
                        });
                }
                handlerCallback(null, self.stopRequested === false);
            })
            .catch(function (err) {
                logger.error('Fatal error', err);
                handlerCallback(err, false);
            });
    }

    function branchStatusHandler(branchStatus /*, commitQueue, updateQueue*/) {
        //TODO check how it should work
        logger.debug('New branchStatus', branchStatus);
    }

    // API functions
    this.start = function (callback) {
        if (self.startRequested === false) {
            startDeferred = Q.defer();
            self.startRequested = true;

            storage.openBranch(project.projectId, branchName, onUpdate, branchStatusHandler,
                function (err/*, latestCommitData*/) {
                    if (err) {
                        startDeferred.reject(err);
                        return;
                    }
                    self.branchIsOpen = true;
                    startDeferred.resolve();
                }
            );
        }

        return startDeferred.promise.nodeify(callback);
    };

    this.stop = function (callback) {
        if (self.stopRequested === false) {
            stopDeferred = Q.defer();
            self.stopRequested = true;

            storage.closeBranch(project.projectId, branchName, function (err) {
                self.branchIsOpen = false;
                if (err) {
                    stopDeferred.reject(err);
                } else {
                    stopDeferred.resolve();
                }
            });
        }

        return stopDeferred.promise.nodeify(callback);
    };

    this.queryAddOn = function (addOnId, commitHash, queryParams, callback) {
        var deferred = Q.defer();
        deferred.reject(new Error('queryAddOn not implemented yet!'));
        return deferred.promise.nodeify(callback);
    };
}

module.exports = BranchMonitor;<|endoftext|>


<commit_before>const { investments } = require('../../../../../src/lib/urls')
const fixtures = require('../../fixtures')
const selectors = require('../../../../selectors')

describe('LEP add Investment Project interaction', () => {
  context('The browser URL has updated', () => {
    before(() => {
      cy.visit(
        investments.projects.interactions.index(
          fixtures.investmentProject.newZoo.id
        )
      )
    })
    it('should have the correct url', () => {
      cy.get('[data-auto-id="Add interaction"]')
        .click()
        .location('pathname')
        .should(
          'eq',
          investments.projects.interactions.createType(
            fixtures.investmentProject.newZoo.id,
            'investment',
            'interaction'
          )
        )
    })
  })

  context('LEP completes the form and clicks "Add interaction"', () => {
    before(() => {
      cy.server().route('POST', '/api-proxy/v3/interaction').as('post')

      cy.visit(
        investments.projects.interactions.createType(
          fixtures.investmentProject.newZoo.id,
          'investment',
          'interaction'
        )
      )
    })

    it('should add an interaction', () => {
      const subject = 'The best Investment Project interaction'
      const formSelectors = selectors.interactionForm

      cy.contains('Add interaction for Mars Exports Ltd')
        .get(formSelectors.service)
        .select('Investment - Services')
        .get(formSelectors.contact)
        .selectTypeaheadOption('Fred Peterson')
        .get(formSelectors.communicationChannel)
        .selectTypeaheadOption('Email/Website')
        .get(formSelectors.subject)
        .type(subject)
        .get(formSelectors.notes)
        .type('Conversation about Investment services')
        .get(formSelectors.policyFeedbackNo)
        .click()
        .get(formSelectors.add)
        .click()
        .wait('@post')
        .should((xhr) => {
          expect(xhr.status, 'successful POST').to.equal(201)
        })

      cy.contains('h1', subject)
    })
  })
})
<commit_msg>Patch LEP test still using old v3 endpoint<commit_after>const { investments } = require('../../../../../src/lib/urls')
const fixtures = require('../../fixtures')
const selectors = require('../../../../selectors')

describe('LEP add Investment Project interaction', () => {
  context('The browser URL has updated', () => {
    before(() => {
      cy.visit(
        investments.projects.interactions.index(
          fixtures.investmentProject.newZoo.id
        )
      )
    })
    it('should have the correct url', () => {
      cy.get('[data-auto-id="Add interaction"]')
        .click()
        .location('pathname')
        .should(
          'eq',
          investments.projects.interactions.createType(
            fixtures.investmentProject.newZoo.id,
            'investment',
            'interaction'
          )
        )
    })
  })

  context('LEP completes the form and clicks "Add interaction"', () => {
    before(() => {
      cy.server().route('POST', '/api-proxy/v4/interaction').as('post')

      cy.visit(
        investments.projects.interactions.createType(
          fixtures.investmentProject.newZoo.id,
          'investment',
          'interaction'
        )
      )
    })

    it('should add an interaction', () => {
      const subject = 'The best Investment Project interaction'
      const formSelectors = selectors.interactionForm

      cy.contains('Add interaction for Mars Exports Ltd')
        .get(formSelectors.service)
        .select('Investment - Services')
        .get(formSelectors.contact)
        .selectTypeaheadOption('Fred Peterson')
        .get(formSelectors.communicationChannel)
        .selectTypeaheadOption('Email/Website')
        .get(formSelectors.subject)
        .type(subject)
        .get(formSelectors.notes)
        .type('Conversation about Investment services')
        .get(formSelectors.policyFeedbackNo)
        .click()
        .get(formSelectors.add)
        .click()
        .wait('@post')
        .should((xhr) => {
          expect(xhr.status, 'successful POST').to.equal(201)
        })

      cy.contains('h1', subject)
    })
  })
})
<|endoftext|>


<commit_before>"use strict";

const Node = require("./Node.js"),
	ID = require("./ID.js");

class RemoteNode {
	constructor(chord, id, optConn){
		this.chord = chord;
		this.id = id;

		//ONLY FINGERS SHOULD HAVE CONNECTIONS.
		this.connection = optConn;
		//TODO
	}

	getSuccessor(){
		//Return an ID, then create a remotenode from that.
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "getSuccessor", [])
				.then(result => resolve((result)? this.chord.obtainRemoteNode(result) : result),
					reason => reject(reason)
				);
		});
	}

	setSuccessor(s){
		//Send them an ID, return the remotenode supplied.
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "setSuccessor", [ID.coerceString(s.id)])
				.then(result => resolve(s),
					reason => reject(reason)
				);
		});
	}

	getPredecessor(){
		//Return an ID, then create a remotenode from that.
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "getPredecessor", [])
				.then(result => resolve((result)? this.chord.obtainRemoteNode(result) : result),
					reason => reject(reason)
				);
		});
	}

	setPredecessor(p){
		//Send them an ID, return the remotenode supplied.
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "setPredecessor", [ID.coerceString(p.id)])
				.then(result => resolve(p),
					reason => reject(reason)
				);
		});
	}

	updateFingerTable(foreignNode, index){
		return this.chord.rcm.call(this.id, "updateFingerTable", [ID.coerceString(foreignNode.id), index]);
	}

	findSuccessor(id){
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "findSuccessor", [ID.coerceString(id)])
				.then(result => resolve(this.chord.obtainRemoteNode(result)),
					reason => reject(reason)
				);
		});
	}

	findPredecessor(id){
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "findPredecessor", [ID.coerceString(id)])
				.then(result => resolve(this.chord.obtainRemoteNode(result)),
					reason => reject(reason)
				);
		});
	}

	closestPrecedingFinger(id){
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "closestPrecedingFinger", [ID.coerceString(id)])
				.then(result => resolve(this.chord.obtainRemoteNode(result)),
					reason => reject(reason)
				);
		});
	}

	notify(nPrime){
		return this.chord.rcm.call(this.id, "notify", [ID.coerceString(nPrime.id)]);
	}

	//Custom

	message(id, msg){
		if(this.connection
			&& this.connection.connection
			&& (this.connection.connection.iceConnectionState === "connected"
			|| this.connection.connection.iceConnectionState === "completed")
			)
			this.connection.send(JSON.stringify({id, data: msg}));
		else {
			console.log(`Creating new connection to ${id} - none found or not open.`);

			this.chord.smartConnectToNode(this.id, this)
				.then(node => {
					this.chord.message(id, msg);
				},
				reason => {
					console.log("Failed to create new connection to remote node.")
				});
		}
	}

	unlinkClient(idString){
		return this.chord.rcm.call(this.id, "unlinkClient", [idString]);
	}

	//Item management

	lookup(id){
		//TODO
	}

	add(id){
		//TODO
	}

}

module.exports = RemoteNode;<commit_msg>Initial proxy implementation.<commit_after>"use strict";

const Node = require("./Node.js"),
	ID = require("./ID.js");

class RemoteNode {
	constructor(chord, id, optConn){
		this.chord = chord;
		this.id = id;

		//ONLY FINGERS SHOULD HAVE CONNECTIONS.
		this.connection = optConn;
		//TODO
	}

	getSuccessor(){
		//Return an ID, then create a remotenode from that.
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "getSuccessor", [])
				.then(result => resolve((result)? this.chord.obtainRemoteNode(result) : result),
					reason => reject(reason)
				);
		});
	}

	setSuccessor(s){
		//Send them an ID, return the remotenode supplied.
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "setSuccessor", [ID.coerceString(s.id)])
				.then(result => resolve(s),
					reason => reject(reason)
				);
		});
	}

	getPredecessor(){
		//Return an ID, then create a remotenode from that.
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "getPredecessor", [])
				.then(result => resolve((result)? this.chord.obtainRemoteNode(result) : result),
					reason => reject(reason)
				);
		});
	}

	setPredecessor(p){
		//Send them an ID, return the remotenode supplied.
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "setPredecessor", [ID.coerceString(p.id)])
				.then(result => resolve(p),
					reason => reject(reason)
				);
		});
	}

	updateFingerTable(foreignNode, index){
		return this.chord.rcm.call(this.id, "updateFingerTable", [ID.coerceString(foreignNode.id), index]);
	}

	findSuccessor(id){
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "findSuccessor", [ID.coerceString(id)])
				.then(result => resolve(this.chord.obtainRemoteNode(result)),
					reason => reject(reason)
				);
		});
	}

	findPredecessor(id){
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "findPredecessor", [ID.coerceString(id)])
				.then(result => resolve(this.chord.obtainRemoteNode(result)),
					reason => reject(reason)
				);
		});
	}

	closestPrecedingFinger(id){
		return new Promise((resolve, reject) => {
			this.chord.rcm.call(this.id, "closestPrecedingFinger", [ID.coerceString(id)])
				.then(result => resolve(this.chord.obtainRemoteNode(result)),
					reason => reject(reason)
				);
		});
	}

	notify(nPrime){
		return this.chord.rcm.call(this.id, "notify", [ID.coerceString(nPrime.id)]);
	}

	//Custom

	message(id, msg){
		if(this.isConnected())
			this.connection.send(JSON.stringify({id, data: msg}));
		else {
			console.log(`Creating new connection to ${id} - none found or not open.`);

			this.chord.smartConnectToNode(this.id, this)
				.then(node => {
					this.chord.message(id, msg);
				},
				reason => {
					console.log("Failed to create new connection to remote node.")
				});
		}
	}

	isConmnected() {
		return this.connection
			&& this.connection.connection
			&& (this.connection.connection.iceConnectionState === "connected"
			|| this.connection.connection.iceConnectionState === "completed");
	}

	unlinkClient(idString){
		return this.chord.rcm.call(this.id, "unlinkClient", [idString]);
	}

	//Item management

	lookup(id){
		//TODO
	}

	add(id){
		//TODO
	}

}

module.exports = RemoteNode;<|endoftext|>


<commit_before>ManageIQ.angular.app.controller('keyPairCloudFormController', ['$http', '$scope', 'keyPairFormId', 'miqService', function($http, $scope, keyPairFormId, miqService) {
    var vm = this;
    var init = function() {
        vm.keyPairModel = {
            name: '',
            public_key: '',
            ems_id: ''
        };
        vm.formId = keyPairFormId;
        vm.afterGet = false;
        vm.modelCopy = angular.copy( vm.keyPairModel );
        vm.model = 'keyPairModel';
        vm.ems_choices = [];
        vm.saveable = miqService.saveable;
        ManageIQ.angular.scope = vm;

        miqService.sparkleOn();
        $http.get('/auth_key_pair_cloud/ems_form_choices')
          .then(getAuthKeyPairCloudFormDataComplete)
          .catch(miqService.handleFailure);

        if (keyPairFormId == 'new') {
            vm.newRecord = true;
        } else {
            vm.newRecord = false;
        }
    };

    var keyPairEditButtonClicked = function(buttonName, serializeFields) {
        miqService.sparkleOn();

        var url = '/auth_key_pair_cloud/create/' + keyPairFormId + '?button=' + buttonName;
        vm.keyPairModel.ems_id = vm.keyPairModel.ems.id;
        if (serializeFields) {
            miqService.miqAjaxButton(url, miqService.serializeModel(vm.keyPairModel));
        } else {
            miqService.miqAjaxButton(url, false);
        }
        miqService.sparkleOff();
    };

    vm.cancelClicked = function() {
        keyPairEditButtonClicked('cancel', false);
        vm.angularForm.$setPristine(true);
    };

    vm.resetClicked = function() {
        vm.keyPairModel = angular.copy( vm.modelCopy );
        vm.angularForm.$setPristine(true);
        miqService.miqFlash("warn", __("All changes have been reset"));
    };

    vm.saveClicked = function() {
        keyPairEditButtonClicked('save', true);
        vm.angularForm.$setPristine(true);
    };

    vm.addClicked = function() {
        vm.saveClicked();
    };

    function getAuthKeyPairCloudFormDataComplete(response) {
      var data = response.data;

      vm.ems_choices = data.ems_choices;
      if (vm.ems_choices.length > 0) {
        vm.keyPairModel.ems = vm.ems_choices[0];
      }
      vm.afterGet = true;
      miqService.sparkleOff();
    }

    init();
}]);
<commit_msg>Auth key pair form - scope defined but never used<commit_after>ManageIQ.angular.app.controller('keyPairCloudFormController', ['$http', 'keyPairFormId', 'miqService', function($http, keyPairFormId, miqService) {
    var vm = this;
    var init = function() {
        vm.keyPairModel = {
            name: '',
            public_key: '',
            ems_id: ''
        };
        vm.formId = keyPairFormId;
        vm.afterGet = false;
        vm.modelCopy = angular.copy( vm.keyPairModel );
        vm.model = 'keyPairModel';
        vm.ems_choices = [];
        vm.saveable = miqService.saveable;
        ManageIQ.angular.scope = vm;

        miqService.sparkleOn();
        $http.get('/auth_key_pair_cloud/ems_form_choices')
          .then(getAuthKeyPairCloudFormDataComplete)
          .catch(miqService.handleFailure);

        if (keyPairFormId == 'new') {
            vm.newRecord = true;
        } else {
            vm.newRecord = false;
        }
    };

    var keyPairEditButtonClicked = function(buttonName, serializeFields) {
        miqService.sparkleOn();

        var url = '/auth_key_pair_cloud/create/' + keyPairFormId + '?button=' + buttonName;
        vm.keyPairModel.ems_id = vm.keyPairModel.ems.id;
        if (serializeFields) {
            miqService.miqAjaxButton(url, miqService.serializeModel(vm.keyPairModel));
        } else {
            miqService.miqAjaxButton(url, false);
        }
        miqService.sparkleOff();
    };

    vm.cancelClicked = function() {
        keyPairEditButtonClicked('cancel', false);
        vm.angularForm.$setPristine(true);
    };

    vm.resetClicked = function() {
        vm.keyPairModel = angular.copy( vm.modelCopy );
        vm.angularForm.$setPristine(true);
        miqService.miqFlash("warn", __("All changes have been reset"));
    };

    vm.saveClicked = function() {
        keyPairEditButtonClicked('save', true);
        vm.angularForm.$setPristine(true);
    };

    vm.addClicked = function() {
        vm.saveClicked();
    };

    function getAuthKeyPairCloudFormDataComplete(response) {
      var data = response.data;

      vm.ems_choices = data.ems_choices;
      if (vm.ems_choices.length > 0) {
        vm.keyPairModel.ems = vm.ems_choices[0];
      }
      vm.afterGet = true;
      miqService.sparkleOff();
    }

    init();
}]);
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * module UI
 *
 ******************************************************************************/

var UI = function() {
  return {

    KEYCODE_ENTER : 13,
    KEYCODE_ESC   : 27,

    MIN_IE_VERSION : 8.0,

    init : function() {
      UI.check_environment();
      Bridge.init();
      UI.add_system_hooks();
      UI.redirect_links();
      // Initialize controls. Some need some global events to function properly.
      // (?) Automate these call?
      Window.init();
      Button.init();
      RadioButton.init();
      // Disable native browser functions to make the dialog appear more native.
      UI.disable_select();
      UI.disable_context_menu();
      // Ready Event
      Sketchup.callback('SKUI::Window.on_ready')
    },

    /* Ensure links are opened in the default browser. This ensures that the
     * WebDialog doesn't replace the content with the target URL.
     */
    check_environment : function() {
      // Safari don't include a version number. So we cannot test that. But most
      // likely it'll be more up to date and compatible than IE.
      var pattern = /msie\s+(\d+\.\d+)/i
      var result = pattern.exec( navigator.userAgent );
      if ( result && parseFloat(result[1]) < UI.MIN_IE_VERSION ) {
        var $warning = $('
');
        var app = navigator.appName;
        $warning.text( 'A newer version of ' + app + 'is required for SKUI to' +
          ' function properly.' );
        $warning.appendTo( $('body') );
      }
    },

    /* Ensure links are opened in the default browser. This ensures that the
     * WebDialog doesn't replace the content with the target URL.
     */
    redirect_links : function() {
      $(document).on('click', 'a[href]', function()
      {
        Sketchup.callback('SKUI::Window.on_open_url', this.href)
        return false;
      } );
    },

    /* Disables text selection on elements other than input type elements where
     * it makes sense to allow selections. This mimics native windows.
     */
    disable_select : function() {
      $(document).on('mousedown selectstart', function(e) {
        return $(e.target).is('input, textarea, select, option');
      });
    },

    /* Disables the context menu with the exception for textboxes in order to
     * mimic native windows.
     */
    disable_context_menu : function() {
      $(document).on('contextmenu', function(e) {
        return $(e.target).is('input[type=text], textarea');
      });
    },

    /* Adds a platform specific class to the BODY element that can be used as a
     * hook for CSS to make platform adjustments.
     */
    add_system_hooks : function() {
      if ( Sketchup.platform() == 'PC' ) {
        $('body').addClass('platform-windows');
      } else {
        $('body').addClass('platform-osx');
      }
    },

    /* Adds a control to the window. Called from the Ruby side with a JSON
     * object describing the control.
     */
    add_control : function(properties) {
      if ( properties.type in UI ) {
        control_class = UI[properties.type];
        control_class.add( properties )
        return true;
      } else {
        alert( 'Invalid Control Type: ' + properties.type );
        return false;
      }
    },

    /* Attaches an event to the control. Used by the control classes to set up
     * the events that is relayed back to the Ruby side.
     *
     * The optional `$child` argument is used when the event is coming from a
     * child DOM element.
     */
    add_event : function( eventname, $control, $child ) {
      control = $child || $control
      control.on( eventname, function( event ) {
        var args = new Array();
        var $c = $(this);
        // Prevent events if control is disabled
        // (?) Find parent of any sub-control?
        if ( $c.hasClass('disabled') ) {
          event.stopPropagation();
          event.preventDefault();
          return false;
        }
        /*
        // http://api.jquery.com/category/events/event-object/
        switch ( eventname )
        {
        case 'click':
          args[0] = event.pageX;
          args[1] = event.pageY;
          break;
        }
        */
        var ui_id = $control.attr( 'id' );
        // Defer some events to allow content to update.
        // (i) When IE8 is not supported longer these events might be deprecated
        //     in favour of HTML5's `input` event.
        var defer_events = [ 'copy', 'cut', 'paste' ];
        if ( $.inArray( eventname, defer_events ) ) {
          setTimeout( function() {
            Sketchup.control_callback( ui_id, eventname, args );
          }, 0 );
        } else {
          Sketchup.control_callback( ui_id, eventname, args );
        }
        return true;
      } );
    },

    /* Returns a Control instance from a jQuery or DOM object.
     */
    get_control : function( jQuery_or_id ) {
      var $control = $( jQuery_or_id );
      var control_class_string = $control.data( 'control_class' );
      var control_class = eval( control_class_string );
      var control = new control_class( $control );
      return control;
    },

    /* Removes a control from the window. Called from the Ruby side.
     */
    remove_control : function( control ) {
      var $control = get_jQuery_object(control);
      $control.remove();
      return true;
    },

    /* Updates the given control with the given JSON properties object. The
     * control argument can be either a jQuery object or a string representing
     * the ID of the DOM element.
     */
    update_properties : function( control_or_ui_id, properties ) {
      var $control = get_jQuery_object( control_or_ui_id );
      if ( properties.type in UI ) {
        var control_class = UI[properties.type];
        var control = new control_class( $control );
        control.update( properties );
        return true;
      } else {
        alert( 'Invalid Control Type: ' + properties.type );
        return false;
      }
    }

  };

  /* PRIVATE */

  /* Returns a jQuery object given a jQuery object or DOM id string.
   */
  function get_jQuery_object( id_or_object ) {
    if ( $.type( id_or_object ) == 'string' ) {
      return $( '#' + id_or_object );
    }
    else {
      return id_or_object;
    }
  }

}(); // UI<commit_msg>Improved IE version detection. IE11 changed the rules again. Closes #92.<commit_after>/*******************************************************************************
 *
 * module UI
 *
 ******************************************************************************/

var UI = function() {
  return {

    KEYCODE_ENTER : 13,
    KEYCODE_ESC   : 27,

    MIN_IE_VERSION : 8.0,

    init : function() {
      UI.check_environment();
      Bridge.init();
      UI.add_system_hooks();
      UI.redirect_links();
      // Initialize controls. Some need some global events to function properly.
      // (?) Automate these call?
      Window.init();
      Button.init();
      RadioButton.init();
      // Disable native browser functions to make the dialog appear more native.
      UI.disable_select();
      UI.disable_context_menu();
      // Ready Event
      Sketchup.callback('SKUI::Window.on_ready')
    },

    /* Checks for old versions of the browser engine and warns users of older
     * versions that their browser is not supported.
     * This isn't using feature testing because the requirements is based on
     * CSS support, not HTML or JS support.
     */
    check_environment : function() {
      // Safari don't include a version number. So we cannot test that. But most
      // likely it'll be more up to date and compatible than IE.
      //
      // IE11 changed the user-agent string. The MSDN docs says 'msie' has been
      // dropped, but in the SketchUp webdialog it still appear:
      // https://github.com/thomthom/SKUI/issues/92#issuecomment-37624654
      // However, the version number is missing, so we try to pick that from
      // the document mode instead.
      // I haven't found any info to how the embedded IE engines behaves - all I
      // know is that it has different rules for compatibility.
      var version = 0.0;
      var is_IE = false;
      if ( document.documentMode ) {
        // Internet Explorer 8+.
        version = document.documentMode;
        is_IE = true;
        // Check that documentMode matches with the Trident token  just in case
        // there is a way for the user to force some compatibility mode.
        // In which case a different message should be displayed.
        // IE8  => Trident/4.0
        // IE9  => Trident/5.0
        // IE10 => Trident/6.0
        // IE11 => Trident/7.0
        var trident_pattern = /\sTrident\/(\d+\.\d+);/;
        var trident = trident_pattern.exec( navigator.userAgent );
        var real_version =  parseFloat(trident[1]) + 4; // Bold assumption?
        if ( version < UI.MIN_IE_VERSION && version != real_version ) {
          var $warning = $('
');
          $warning.text( 'Internet Explorer (' + real_version + ') has been ' +
            'forced into compatibility mode (' + version + ') which prevents ' +
            'SKUI from functioning properly.' );
          $warning.appendTo( $('body') );
          return;
        }
      } else {
        // Internet Explorer before version 8.
        var ie_pattern = /msie\s+(\d+\.\d+)/i;
        var ie_result = ie_pattern.exec( navigator.userAgent );
        if (ie_result) {
          version = parseFloat(ie_result[1]);
          is_IE = true;
        }
      }
      if ( is_IE && version < UI.MIN_IE_VERSION ) {
        var $warning = $('
');
        // In IE11 navigator.appName now returns "Netscape". Oh joy!
        $warning.text( 'Detected Internet Explorer ' + version + '. At least ' +
          'version ' + UI.MIN_IE_VERSION + ' is required for SKUI to ' +
          'function properly.' );
        $warning.appendTo( $('body') );
      }
    },

    /* Ensure links are opened in the default browser. This ensures that the
     * WebDialog doesn't replace the content with the target URL.
     */
    redirect_links : function() {
      $(document).on('click', 'a[href]', function()
      {
        Sketchup.callback('SKUI::Window.on_open_url', this.href)
        return false;
      } );
    },

    /* Disables text selection on elements other than input type elements where
     * it makes sense to allow selections. This mimics native windows.
     */
    disable_select : function() {
      $(document).on('mousedown selectstart', function(e) {
        return $(e.target).is('input, textarea, select, option');
      });
    },

    /* Disables the context menu with the exception for textboxes in order to
     * mimic native windows.
     */
    disable_context_menu : function() {
      $(document).on('contextmenu', function(e) {
        return $(e.target).is('input[type=text], textarea');
      });
    },

    /* Adds a platform specific class to the BODY element that can be used as a
     * hook for CSS to make platform adjustments.
     */
    add_system_hooks : function() {
      if ( Sketchup.platform() == 'PC' ) {
        $('body').addClass('platform-windows');
      } else {
        $('body').addClass('platform-osx');
      }
    },

    /* Adds a control to the window. Called from the Ruby side with a JSON
     * object describing the control.
     */
    add_control : function(properties) {
      if ( properties.type in UI ) {
        control_class = UI[properties.type];
        control_class.add( properties )
        return true;
      } else {
        alert( 'Invalid Control Type: ' + properties.type );
        return false;
      }
    },

    /* Attaches an event to the control. Used by the control classes to set up
     * the events that is relayed back to the Ruby side.
     *
     * The optional `$child` argument is used when the event is coming from a
     * child DOM element.
     */
    add_event : function( eventname, $control, $child ) {
      control = $child || $control
      control.on( eventname, function( event ) {
        var args = new Array();
        var $c = $(this);
        // Prevent events if control is disabled
        // (?) Find parent of any sub-control?
        if ( $c.hasClass('disabled') ) {
          event.stopPropagation();
          event.preventDefault();
          return false;
        }
        /*
        // http://api.jquery.com/category/events/event-object/
        switch ( eventname )
        {
        case 'click':
          args[0] = event.pageX;
          args[1] = event.pageY;
          break;
        }
        */
        var ui_id = $control.attr( 'id' );
        // Defer some events to allow content to update.
        // (i) When IE8 is not supported longer these events might be deprecated
        //     in favour of HTML5's `input` event.
        var defer_events = [ 'copy', 'cut', 'paste' ];
        if ( $.inArray( eventname, defer_events ) ) {
          setTimeout( function() {
            Sketchup.control_callback( ui_id, eventname, args );
          }, 0 );
        } else {
          Sketchup.control_callback( ui_id, eventname, args );
        }
        return true;
      } );
    },

    /* Returns a Control instance from a jQuery or DOM object.
     */
    get_control : function( jQuery_or_id ) {
      var $control = $( jQuery_or_id );
      var control_class_string = $control.data( 'control_class' );
      var control_class = eval( control_class_string );
      var control = new control_class( $control );
      return control;
    },

    /* Removes a control from the window. Called from the Ruby side.
     */
    remove_control : function( control ) {
      var $control = get_jQuery_object(control);
      $control.remove();
      return true;
    },

    /* Updates the given control with the given JSON properties object. The
     * control argument can be either a jQuery object or a string representing
     * the ID of the DOM element.
     */
    update_properties : function( control_or_ui_id, properties ) {
      var $control = get_jQuery_object( control_or_ui_id );
      if ( properties.type in UI ) {
        var control_class = UI[properties.type];
        var control = new control_class( $control );
        control.update( properties );
        return true;
      } else {
        alert( 'Invalid Control Type: ' + properties.type );
        return false;
      }
    }

  };

  /* PRIVATE */

  /* Returns a jQuery object given a jQuery object or DOM id string.
   */
  function get_jQuery_object( id_or_object ) {
    if ( $.type( id_or_object ) == 'string' ) {
      return $( '#' + id_or_object );
    }
    else {
      return id_or_object;
    }
  }

}(); // UI
<|endoftext|>