<commit_before>/**
defines the OXI Application classs
*/

OXI.Application = Ember.Application.extend(
{
   LOG_TRANSITIONS: true,
   rootElement: null,//read from config
   serverUrl:null,//read from config

   user_logged_in: false,
   user:null,
   username:function(){
      if(this.user){
         return this.user.login;
      }else{
         return '';
      }
   }.property('user'),

   //store currentPath (of router) to have a observable property for navigation-highlighting:
   currentPath: '',
   currentRootPath:'',
   SideNavs : {},
   CurrentSideNav : null,
   sideTreeStructure: {},

   ApplicationController : Ember.Controller.extend({
      updateCurrentPath: function() {
         App.setCurrentPath( this.get('currentPath'));
      }.observes('currentPath')
   }),

   BadUrlRoute: Ember.Route.extend({
        beforeModel: function(transition) {
            Ember.debug('BadUrlRoute '+location.hash+' check transition');

            App.set('original_target',location.hash.substr(1));
            if(!App.user_logged_in){
                /*
                var loginController = this.controllerFor('login');

                loginController.set('original_target', original_target);
                */
                this.transitionTo('login');
            }else{
                 this.transitionTo('notfound');
            }
        }
  }),

  NotfoundRoute: Ember.Route.extend({

       renderTemplate: function(controller, model) {
         var original_target = App.get('original_target');
         if(original_target){
            controller.set('original_target',original_target);
            App.set('original_target','');
         }
         this.render('notfound');
      }
  }),

   SideNavItemView : Ember.View.extend({
                      tagName: "li"
   }),

    MainNavItemView : Ember.View.extend({
          tagName: "li",
          classNames:['dropdown']
    }),

   ready: function() {
      Ember.debug('Application ready');
   },

   init:function(){
      this._super();
      this.rootElement = OXI.Config.get('rootElement');
      this.serverUrl = OXI.Config.get('serverUrl');
   },

   logout:function(){
      this.set('user',null);
      this.set('user_logged_in',false);
   },

   login:function(user){
      this.set('user',user);
      this.set('user_logged_in',true);
   },

   checkSideStructure: function(callback){
      Ember.debug('Application checkSideStructure');
      this.set('CurrentSideNav',null);
      this.set('SideNavs',{});
      this.set('sideTreeStructure',{});
      //this.sideTreeStructure = testStructure;
      var App = this;
      return this.callServer({action:'get_structure'})
      .done(function(json){
         js_debug('sidestructure retrieved');
         //js_debug( json,2);
         if(json.structure){
            App.set('sideTreeStructure', json.structure);
         }else{
            App.applicationError('call to get_structure failed!',json);
         }
         if(json.user){
              App.login(json.user);
         }
      });
   },

   applicationError: function(msg,data){
      alert('Application-Error: ' + msg);
      js_debug(data);
   },

   callServer: function(params, callback,debug){
      var app = this;
      return jQuery.ajax({
         type: "GET",
         url: this.serverUrl,
         dataType: "json",
         data:params,
         success: function(json, textStatus){
            if(!json){
               ajaxErrorAlert(app.serverUrl,textStatus,'no json returned');
               return;
            }
            if(debug)js_debug(json);

            if(typeof(callback!='undefined') && callback)callback(json);

         },
         error: function(XMLHttpRequest, textStatus){
            //js_debug(XMLHttpRequest);
            ajaxErrorAlert(app.serverUrl,textStatus,XMLHttpRequest.responseText);
         }
      });
   },

   setCurrentPath:function(currentPath){
      js_debug('updateCurrentPath: '+ currentPath );
      this.set('currentPath',currentPath);
      var currentRootPath = currentPath.split('.')[0];
      if(currentRootPath =='index')currentRootPath='home';
      this.set('currentRootPath',currentRootPath);
      this.set('CurrentSideNav',this.SideNavs[currentRootPath]);
   },

   initRouter: function(){
      var App = this;
      Ember.debug('initRouter');
      this.Router.map(function() {
         Ember.debug('App.Router.map');
         this.route('login');
         this.route('logout');
         this.route('notfound');
         App.set('NavArrayController', Ember.ArrayController.create({
              content: Ember.A([])
           }));
         var i,j;
         for(i=0;i<App.sideTreeStructure.length;i++){
            var ressource = App.sideTreeStructure[i];
            Ember.debug('add to Top Nav: '+ressource.key);
            if(!ressource.entries || !ressource.entries.length){
               this.route(ressource.key);
               App.NavArrayController.pushObject(
               OXI.NavRessource.create({
                  rootPath : ressource.key,
                  goto:ressource.key,
                  title:     ressource.label,
                  has_entries: false
               })
               );

            }else{

               this.resource(ressource.key,  function() {

                  var subLevelControler = Ember.ArrayController.create({ content: Ember.A([])});
                  for(j=0;j<ressource.entries.length;j++){
                     var route = ressource.entries[j];
                     this.route(route.key);
                     subLevelControler.pushObject(
                     OXI.NavItem.create({
                        title: route.label,
                        goto: ressource.key+'.'+route.key
                     })
                     );
                  }

                  App.NavArrayController.pushObject(
                  OXI.NavRessource.create({
                     rootPath : ressource.key,
                     goto:ressource.key,
                     title:     ressource.label,
                     has_entries: true,
                     entries : subLevelControler
                  })
                  );
                  App.SideNavs[ressource.key] = subLevelControler;
               });
            }//ende if/else entries
         }//for

         this.route('bad_url', { path: '/*badurl' }); // Catch everything else!

      });//App.Router.map
   }//initRouter

});<commit_msg>Change hash key for user info (user.login -> user.name)<commit_after>/**
defines the OXI Application classs
*/

OXI.Application = Ember.Application.extend(
{
   LOG_TRANSITIONS: true,
   rootElement: null,//read from config
   serverUrl:null,//read from config

   user_logged_in: false,
   user:null,
   username:function(){
      if(this.user){
         return this.user.name;
      }else{
         return '';
      }
   }.property('user'),

   //store currentPath (of router) to have a observable property for navigation-highlighting:
   currentPath: '',
   currentRootPath:'',
   SideNavs : {},
   CurrentSideNav : null,
   sideTreeStructure: {},

   ApplicationController : Ember.Controller.extend({
      updateCurrentPath: function() {
         App.setCurrentPath( this.get('currentPath'));
      }.observes('currentPath')
   }),

   BadUrlRoute: Ember.Route.extend({
        beforeModel: function(transition) {
            Ember.debug('BadUrlRoute '+location.hash+' check transition');

            App.set('original_target',location.hash.substr(1));
            if(!App.user_logged_in){
                /*
                var loginController = this.controllerFor('login');

                loginController.set('original_target', original_target);
                */
                this.transitionTo('login');
            }else{
                 this.transitionTo('notfound');
            }
        }
  }),

  NotfoundRoute: Ember.Route.extend({

       renderTemplate: function(controller, model) {
         var original_target = App.get('original_target');
         if(original_target){
            controller.set('original_target',original_target);
            App.set('original_target','');
         }
         this.render('notfound');
      }
  }),

   SideNavItemView : Ember.View.extend({
                      tagName: "li"
   }),

    MainNavItemView : Ember.View.extend({
          tagName: "li",
          classNames:['dropdown']
    }),

   ready: function() {
      Ember.debug('Application ready');
   },

   init:function(){
      this._super();
      this.rootElement = OXI.Config.get('rootElement');
      this.serverUrl = OXI.Config.get('serverUrl');
   },

   logout:function(){
      this.set('user',null);
      this.set('user_logged_in',false);
   },

   login:function(user){
      this.set('user',user);
      this.set('user_logged_in',true);
   },

   checkSideStructure: function(callback){
      Ember.debug('Application checkSideStructure');
      this.set('CurrentSideNav',null);
      this.set('SideNavs',{});
      this.set('sideTreeStructure',{});
      //this.sideTreeStructure = testStructure;
      var App = this;
      return this.callServer({action:'bootstrap.structure'})
      .done(function(json){
         js_debug('sidestructure retrieved');
         //js_debug( json,2);
         if(json.structure){
            App.set('sideTreeStructure', json.structure);
         }else{
            App.applicationError('call to bootstrap.structure failed!',json);
         }
         if(json.user){
              App.login(json.user);
         }
      });
   },

   applicationError: function(msg,data){
      alert('Application-Error: ' + msg);
      js_debug(data);
   },

   callServer: function(params, callback,debug){
      var app = this;
      return jQuery.ajax({
         type: "GET",
         url: this.serverUrl,
         dataType: "json",
         data:params,
         success: function(json, textStatus){
            if(!json){
               ajaxErrorAlert(app.serverUrl,textStatus,'no json returned');
               return;
            }
            if(debug)js_debug(json);

            if(typeof(callback!='undefined') && callback)callback(json);

         },
         error: function(XMLHttpRequest, textStatus){
            //js_debug(XMLHttpRequest);
            ajaxErrorAlert(app.serverUrl,textStatus,XMLHttpRequest.responseText);
         }
      });
   },

   setCurrentPath:function(currentPath){
      js_debug('updateCurrentPath: '+ currentPath );
      this.set('currentPath',currentPath);
      var currentRootPath = currentPath.split('.')[0];
      if(currentRootPath =='index')currentRootPath='home';
      this.set('currentRootPath',currentRootPath);
      this.set('CurrentSideNav',this.SideNavs[currentRootPath]);
   },

   initRouter: function(){
      var App = this;
      Ember.debug('initRouter');
      this.Router.map(function() {
         Ember.debug('App.Router.map');
         this.route('login');
         this.route('logout');
         this.route('notfound');
         App.set('NavArrayController', Ember.ArrayController.create({
              content: Ember.A([])
           }));
         var i,j;
         for(i=0;i<App.sideTreeStructure.length;i++){
            var ressource = App.sideTreeStructure[i];
            Ember.debug('add to Top Nav: '+ressource.key);
            if(!ressource.entries || !ressource.entries.length){
               this.route(ressource.key);
               App.NavArrayController.pushObject(
               OXI.NavRessource.create({
                  rootPath : ressource.key,
                  goto:ressource.key,
                  title:     ressource.label,
                  has_entries: false
               })
               );

            }else{

               this.resource(ressource.key,  function() {

                  var subLevelControler = Ember.ArrayController.create({ content: Ember.A([])});
                  for(j=0;j<ressource.entries.length;j++){
                     var route = ressource.entries[j];
                     this.route(route.key);
                     subLevelControler.pushObject(
                     OXI.NavItem.create({
                        title: route.label,
                        goto: ressource.key+'.'+route.key
                     })
                     );
                  }

                  App.NavArrayController.pushObject(
                  OXI.NavRessource.create({
                     rootPath : ressource.key,
                     goto:ressource.key,
                     title:     ressource.label,
                     has_entries: true,
                     entries : subLevelControler
                  })
                  );
                  App.SideNavs[ressource.key] = subLevelControler;
               });
            }//ende if/else entries
         }//for

         this.route('bad_url', { path: '/*badurl' }); // Catch everything else!

      });//App.Router.map
   }//initRouter

});<|endoftext|>


<commit_before>angular.module("kitware.cmb.core")
    .controller('cmb.CoreController', ['$scope', 'kw.Girder', '$modal', '$templateCache', '$state', '$stateParams', 'CmbWorkflowHelper', '$mdDialog', '$window', '$mdToast', function ($scope, $girder, $modal, $templateCache, $state, $stateParams, CmbWorkflowHelper, $mdDialog, $window, $mdToast) {
        var machines = [
            { "id": "m3.medium",    "label": "Basic Small",       "cpu": 1, "gpu": 0, "memory": 3.75, "cost": 0.07, "storage": [4] },
            { "id": "m3.large",     "label": "Basic Medium",      "cpu": 2, "gpu": 0, "memory": 7.5,  "cost": 0.14, "storage": [32] },
            { "id": "m3.xlarge",    "label": "Basic Large",       "cpu": 4, "gpu": 0, "memory": 15,   "cost": 0.28, "storage": [40,40] },
            { "id": "m3.2xlarge",   "label": "Basic Extra Large", "cpu": 8, "gpu": 0, "memory": 30,   "cost": 0.56, "storage": [80,80] },

            { "id": "c3.large",     "label": "Compute Small",    "cpu": 2,  "gpu": 0, "memory": 3.75, "cost": 0.105, "storage": [16,16] },
            { "id": "c3.xlarge",    "label": "Compute Medium",   "cpu": 4,  "gpu": 0, "memory": 7.5,  "cost": 0.21,  "storage": [40,40] },
            { "id": "c3.2xlarge",   "label": "Compute Large",    "cpu": 8,  "gpu": 0, "memory": 15,   "cost": 0.42,  "storage": [80,80] },
            { "id": "c3.4xlarge",   "label": "Compute X Large",  "cpu": 16, "gpu": 0, "memory": 30,   "cost": 0.84,  "storage": [160,160] },
            { "id": "c3.8xlarge",   "label": "Compute XX Large", "cpu": 32, "gpu": 0, "memory": 60,   "cost": 1.68,  "storage": [320,320] },

            { "id": "r3.large",     "label": "Memory Small",    "cpu": 2,  "gpu": 0, "memory": 15.25, "cost": 0.175, "storage": [32] },
            { "id": "r3.xlarge",    "label": "Memory Medium",   "cpu": 4,  "gpu": 0, "memory": 30.5,  "cost": 0.350, "storage": [80] },
            { "id": "r3.2xlarge",   "label": "Memory Large",    "cpu": 8,  "gpu": 0, "memory": 61,    "cost": 0.7,   "storage": [160] },
            { "id": "r3.4xlarge",   "label": "Memory X Large",  "cpu": 16, "gpu": 0, "memory": 122,   "cost": 1.4,   "storage": [320] },
            { "id": "r3.8xlarge",   "label": "Memory XX Large", "cpu": 32, "gpu": 0, "memory": 244,   "cost": 2.8,   "storage": [320,320] },

            { "id": "g2.2xlarge",   "label": "Graphic node", "cpu": 8, "gpu": 1, "memory": 15, "cost": 0.65, "storage": [60,60] }
        ];

        // Authentication / User handling -------------------------------------

        $scope.user = $girder.getUser();
        $scope.title = "Cloud HPC";
        $scope.subTitle = "";
        $scope.collection = null;
        $scope.project = null;
        $scope.simulation = null;

        var previousActiveId = {
            collectionName: '',
            projectID: '',
            simulationID: ''
        };

        $scope.$on('$stateChangeSuccess', function(event) {
            var projectId = $stateParams.projectID,
                collectionName = $stateParams.collectionName,
                simulationId = $stateParams.simulationID;

            if(collectionName && previousActiveId.collectionName !== collectionName) {
               $girder.getCollectionFromName(collectionName).success(function(collections){
                    $scope.collection = collections[0];
                    previousActiveId.collectionName = collectionName;
                    CmbWorkflowHelper.getTemplate(collections[0].name);
                }).error(function(){
                    console.log('Error while fetching collection');
                    previousActiveId.collectionName = '';
                    $scope.collection = null;
                });
            }

            if(simulationId && previousActiveId.simulationID !== simulationId) {
               $girder.getItem(simulationId).success(function(simulation){
                    $scope.simulation = simulation;
                    previousActiveId.simulationID = simulationId;
                }).error(function(){
                    console.log('Error while fetching collection');
                    previousActiveId.simulationID = '';
                    $scope.simulation = null;
                });
            }

            if(projectId && previousActiveId.projectID !== projectId) {
                $girder.getFolder(projectId).success(function(project){
                    $scope.project = project;
                    $scope.subTitle = project.name;
                    previousActiveId.projectID = projectId;
                }).error(function(){
                    console.log('Error while fetching project');
                    $scope.subTitle = null;
                    $scope.project = null;
                    previousActiveId.projectID = '';
                });
            }

            if(!projectId) {
                $scope.subTitle = null;
                $scope.project = null;
                previousActiveId.projectID = '';
            }
        });

        $scope.getActiveCollection = function() {
            if($stateParams.collectionName) {
                return $stateParams.collectionName;
            }
            return previousActiveId.collectionName === '' ? null : previousActiveId.collectionName;
        };

        $scope.getActiveProject = function() {
            if($stateParams.projectID) {
                return $stateParams.projectID;
            }
            return previousActiveId.projectID === '' ? null : previousActiveId.projectID;
        };

        $scope.getActiveSimulation = function() {
            if($stateParams.simulationID) {
                return $stateParams.simulationID;
            }
            return previousActiveId.simulationID === '' ? null : previousActiveId.simulationID;
        };

        $scope.logout = function () {
            $girder.logout();
        };

        $scope.login = function (user, password) {
            $girder.login(user, password);
        };

        $scope.runTask = function (event, title, taskName, hasLauncher, callback) {
            var simulation = $scope.simulation,
                collectionName = $scope.collection.name;

            $mdDialog.show({
                controller: ['$scope', '$mdDialog', function($scope, $mdDialog) {
                    $scope.hasLauncher = hasLauncher;
                    $scope.machines = machines;
                    $scope.title = title;
                    $scope.data = angular.copy($window.WorkflowHelper[collectionName]['default-simulation-cluster']);

                    $scope.updateCost = function() {
                        var cost = 0,
                            array = machines,
                            count = array.length;

                        while(count--) {
                            if(array[count].id === $scope.data.type) {
                               cost = array[count].cost;
                               $scope.data.cores =  array[count].cpu;
                            }
                        }

                        cost *= Number($scope.data.size);
                        $scope.data.cost = cost;
                    };
                    $scope.updateCost();

                    $scope.ok = function(response) {
                        // Delegate the start class on the callback function
                        $mdDialog.hide([simulation, response, $girder.getTaskId(collectionName, taskName)]);
                    };

                    $scope.cancel = function() {
                      $mdDialog.cancel();
                    };
                }],
                template: $templateCache.get('cmb/core/tpls/cmb-run-task-dialog.html'),
                targetEvent: event,
            })
            .then(callback, function() {
                // Nothing to do when cancel
            });
        };

        $scope.$on('login', function (event, user) {
            $scope.user = user;
            $state.go('home');
        });

        $scope.$on('login-error', function (event) {
            $scope.user = null;
            $scope.$broadcast('notification-message', {
                type: 'error',
                message: 'Invalid login or password'
            });
        });

        $scope.$on('logout-error', function (event) {
            $scope.user = null;
            $scope.$broadcast('notification-message', {
                type: 'error',
                message: 'The logout action failed'
            });
        });

        $scope.$on('logout', function (event) {
            $scope.user = null;
            $state.go('login');
        });

        if($girder.getUser() === null) {
            $state.go('login');
        }

        $scope.$on('notification-message', function (evt, message) {
            if(message === null) {
                $mdToast.hide();
            } else {
                var percentage = message.type === 'upload' ? Math.floor(100 * message.done / message.total) : 0;
                $mdToast.show(
                    $mdToast.simple()
                        .content( message.type === 'upload' ? (message.file + '  ' + percentage + ' %') : (message.message))
                        .position('bottom left right')
                        .hideDelay(5000)
                );
            }
        });

    }]);
<commit_msg>Make sure we have the task def<commit_after>angular.module("kitware.cmb.core")
    .controller('cmb.CoreController', ['$scope', 'kw.Girder', '$modal', '$templateCache', '$state', '$stateParams', 'CmbWorkflowHelper', '$mdDialog', '$window', '$mdToast', function ($scope, $girder, $modal, $templateCache, $state, $stateParams, CmbWorkflowHelper, $mdDialog, $window, $mdToast) {
        var machines = [
            { "id": "m3.medium",    "label": "Basic Small",       "cpu": 1, "gpu": 0, "memory": 3.75, "cost": 0.07, "storage": [4] },
            { "id": "m3.large",     "label": "Basic Medium",      "cpu": 2, "gpu": 0, "memory": 7.5,  "cost": 0.14, "storage": [32] },
            { "id": "m3.xlarge",    "label": "Basic Large",       "cpu": 4, "gpu": 0, "memory": 15,   "cost": 0.28, "storage": [40,40] },
            { "id": "m3.2xlarge",   "label": "Basic Extra Large", "cpu": 8, "gpu": 0, "memory": 30,   "cost": 0.56, "storage": [80,80] },

            { "id": "c3.large",     "label": "Compute Small",    "cpu": 2,  "gpu": 0, "memory": 3.75, "cost": 0.105, "storage": [16,16] },
            { "id": "c3.xlarge",    "label": "Compute Medium",   "cpu": 4,  "gpu": 0, "memory": 7.5,  "cost": 0.21,  "storage": [40,40] },
            { "id": "c3.2xlarge",   "label": "Compute Large",    "cpu": 8,  "gpu": 0, "memory": 15,   "cost": 0.42,  "storage": [80,80] },
            { "id": "c3.4xlarge",   "label": "Compute X Large",  "cpu": 16, "gpu": 0, "memory": 30,   "cost": 0.84,  "storage": [160,160] },
            { "id": "c3.8xlarge",   "label": "Compute XX Large", "cpu": 32, "gpu": 0, "memory": 60,   "cost": 1.68,  "storage": [320,320] },

            { "id": "r3.large",     "label": "Memory Small",    "cpu": 2,  "gpu": 0, "memory": 15.25, "cost": 0.175, "storage": [32] },
            { "id": "r3.xlarge",    "label": "Memory Medium",   "cpu": 4,  "gpu": 0, "memory": 30.5,  "cost": 0.350, "storage": [80] },
            { "id": "r3.2xlarge",   "label": "Memory Large",    "cpu": 8,  "gpu": 0, "memory": 61,    "cost": 0.7,   "storage": [160] },
            { "id": "r3.4xlarge",   "label": "Memory X Large",  "cpu": 16, "gpu": 0, "memory": 122,   "cost": 1.4,   "storage": [320] },
            { "id": "r3.8xlarge",   "label": "Memory XX Large", "cpu": 32, "gpu": 0, "memory": 244,   "cost": 2.8,   "storage": [320,320] },

            { "id": "g2.2xlarge",   "label": "Graphic node", "cpu": 8, "gpu": 1, "memory": 15, "cost": 0.65, "storage": [60,60] }
        ];

        // Authentication / User handling -------------------------------------

        $scope.user = $girder.getUser();
        $scope.title = "Cloud HPC";
        $scope.subTitle = "";
        $scope.collection = null;
        $scope.project = null;
        $scope.simulation = null;

        var previousActiveId = {
            collectionName: '',
            projectID: '',
            simulationID: ''
        };

        $scope.$on('$stateChangeSuccess', function(event) {
            var projectId = $stateParams.projectID,
                collectionName = $stateParams.collectionName,
                simulationId = $stateParams.simulationID;

            if(collectionName && previousActiveId.collectionName !== collectionName) {
               $girder.getCollectionFromName(collectionName).success(function(collections){
                    $scope.collection = collections[0];
                    previousActiveId.collectionName = collectionName;
                    CmbWorkflowHelper.getTemplate(collections[0].name);
                }).error(function(){
                    console.log('Error while fetching collection');
                    previousActiveId.collectionName = '';
                    $scope.collection = null;
                });
            }

            if(simulationId && previousActiveId.simulationID !== simulationId) {
               $girder.getItem(simulationId).success(function(simulation){
                    $scope.simulation = simulation;
                    previousActiveId.simulationID = simulationId;
                }).error(function(){
                    console.log('Error while fetching collection');
                    previousActiveId.simulationID = '';
                    $scope.simulation = null;
                });
            }

            if(projectId && previousActiveId.projectID !== projectId) {
                $girder.getFolder(projectId).success(function(project){
                    $scope.project = project;
                    $scope.subTitle = project.name;
                    previousActiveId.projectID = projectId;
                }).error(function(){
                    console.log('Error while fetching project');
                    $scope.subTitle = null;
                    $scope.project = null;
                    previousActiveId.projectID = '';
                });
            }

            if(!projectId) {
                $scope.subTitle = null;
                $scope.project = null;
                previousActiveId.projectID = '';
            }
        });

        $scope.getActiveCollection = function() {
            if($stateParams.collectionName) {
                return $stateParams.collectionName;
            }
            return previousActiveId.collectionName === '' ? null : previousActiveId.collectionName;
        };

        $scope.getActiveProject = function() {
            if($stateParams.projectID) {
                return $stateParams.projectID;
            }
            return previousActiveId.projectID === '' ? null : previousActiveId.projectID;
        };

        $scope.getActiveSimulation = function() {
            if($stateParams.simulationID) {
                return $stateParams.simulationID;
            }
            return previousActiveId.simulationID === '' ? null : previousActiveId.simulationID;
        };

        $scope.logout = function () {
            $girder.logout();
        };

        $scope.login = function (user, password) {
            $girder.login(user, password);
        };

        $scope.runTask = function (event, title, taskName, hasLauncher, callback) {
            var simulation = $scope.simulation,
                collectionName = $scope.collection.name;

            $mdDialog.show({
                controller: ['$scope', '$mdDialog', function($scope, $mdDialog) {
                    $scope.hasLauncher = hasLauncher;
                    $scope.machines = machines;
                    $scope.title = title;
                    $scope.data = angular.copy($window.WorkflowHelper[collectionName]['default-simulation-cluster']);

                    $scope.updateCost = function() {
                        var cost = 0,
                            array = machines,
                            count = array.length;

                        while(count--) {
                            if(array[count].id === $scope.data.type) {
                               cost = array[count].cost;
                               $scope.data.cores =  array[count].cpu;
                            }
                        }

                        cost *= Number($scope.data.size);
                        $scope.data.cost = cost;
                    };
                    $scope.updateCost();

                    $scope.ok = function(response) {
                        // Delegate the start class on the callback function
                        $mdDialog.hide([simulation, response, $girder.getTaskId(collectionName, taskName)]);
                    };

                    $scope.cancel = function() {
                      $mdDialog.cancel();
                    };
                }],
                template: $templateCache.get('cmb/core/tpls/cmb-run-task-dialog.html'),
                targetEvent: event,
            })
            .then(callback, function() {
                // Nothing to do when cancel
            });
        };

        $scope.$on('login', function (event, user) {
            $scope.user = user;
            $state.go('home');
            $girder.fetchTaskList();
        });

        $scope.$on('login-error', function (event) {
            $scope.user = null;
            $scope.$broadcast('notification-message', {
                type: 'error',
                message: 'Invalid login or password'
            });
        });

        $scope.$on('logout-error', function (event) {
            $scope.user = null;
            $scope.$broadcast('notification-message', {
                type: 'error',
                message: 'The logout action failed'
            });
        });

        $scope.$on('logout', function (event) {
            $scope.user = null;
            $state.go('login');
        });

        if($girder.getUser() === null) {
            $state.go('login');
        }

        $scope.$on('notification-message', function (evt, message) {
            if(message === null) {
                $mdToast.hide();
            } else {
                var percentage = message.type === 'upload' ? Math.floor(100 * message.done / message.total) : 0;
                $mdToast.show(
                    $mdToast.simple()
                        .content( message.type === 'upload' ? (message.file + '  ' + percentage + ' %') : (message.message))
                        .position('bottom left right')
                        .hideDelay(5000)
                );
            }
        });

    }]);
<|endoftext|>


<commit_before>import { Mixin } from 'ember-metal/mixin';
import alias from 'ember-metal/alias';
import ActionHandler from 'ember-runtime/mixins/action_handler';
import ControllerContentModelAliasDeprecation from 'ember-runtime/mixins/controller_content_model_alias_deprecation';

/**
  @class ControllerMixin
  @namespace Ember
  @uses Ember.ActionHandler
  @private
*/
export default Mixin.create(ActionHandler, ControllerContentModelAliasDeprecation, {
  /* ducktype as a controller */
  isController: true,

  /**
    The object to which actions from the view should be sent.

    For example, when a Handlebars template uses the `{{action}}` helper,
    it will attempt to send the action to the view's controller's `target`.

    By default, the value of the target property is set to the router, and
    is injected when a controller is instantiated. This injection is defined
    in Ember.Application#buildContainer, and is applied as part of the
    applications initialization process. It can also be set after a controller
    has been instantiated, for instance when using the render helper in a
    template, or when a controller is used as an `itemController`. In most
    cases the `target` property will automatically be set to the logical
    consumer of actions for the controller.

    @property target
    @default null
    @private
  */
  target: null,

  container: null,

  parentController: null,

  store: null,

  /**
    The controller's current model. When retrieving or modifying a controller's
    model, this property should be used instead of the `content` property.

    @property model
    @public
   */
  model: null,

  /**
    @private
  */
  content: alias('model')

});
<commit_msg>[DOC release] Make Ember.Controller.target public.<commit_after>import { Mixin } from 'ember-metal/mixin';
import alias from 'ember-metal/alias';
import ActionHandler from 'ember-runtime/mixins/action_handler';
import ControllerContentModelAliasDeprecation from 'ember-runtime/mixins/controller_content_model_alias_deprecation';

/**
  @class ControllerMixin
  @namespace Ember
  @uses Ember.ActionHandler
  @private
*/
export default Mixin.create(ActionHandler, ControllerContentModelAliasDeprecation, {
  /* ducktype as a controller */
  isController: true,

  /**
    The object to which actions from the view should be sent.

    For example, when a Handlebars template uses the `{{action}}` helper,
    it will attempt to send the action to the view's controller's `target`.

    By default, the value of the target property is set to the router, and
    is injected when a controller is instantiated. This injection is defined
    in Ember.Application#buildContainer, and is applied as part of the
    applications initialization process. It can also be set after a controller
    has been instantiated, for instance when using the render helper in a
    template, or when a controller is used as an `itemController`. In most
    cases the `target` property will automatically be set to the logical
    consumer of actions for the controller.

    @property target
    @default null
    @public
  */
  target: null,

  container: null,

  parentController: null,

  store: null,

  /**
    The controller's current model. When retrieving or modifying a controller's
    model, this property should be used instead of the `content` property.

    @property model
    @public
   */
  model: null,

  /**
    @private
  */
  content: alias('model')

});
<|endoftext|>


<commit_before>/* globals $ */
/* eslint-env node, dirigible */

var indexing = require('api/indexing');
var response = require('api/http/response');

var index = indexing.getIndex("myIndex");
var document1 = {
       "id": "1",
       "content": "some cool content 1"
    };
var document2 = {
       "id": "2",
       "content": "some cool content 2"
    };

index.add(document1);
index.add(document2);

var results = index.search("cool");
for (var i=0;i<results.length;i++) {
	var result = results[i];
    response.println("[Found for 'cool']: " + result.id);
}

var results = index.search("1");
for (var i=0;i<results.length;i++) {
	var result = results[i];
    response.println("[Found for '1']: " + result.id);
}

var results = index.search("2");
for (var i=0;i<results.length;i++) {
	var result = results[i];
    response.println("[Found for '2']: " + result.id);
}

index.clear();

response.flush();
response.close();
<commit_msg>small fix<commit_after>/* globals $ */
/* eslint-env node, dirigible */

var indexing = require('api/indexing');
var response = require('api/http/response');

var index = indexing.getIndex("myIndex");
var document1 = {
       "id": "1",
       "content": "some cool content 1"
    };
var document2 = {
       "id": "2",
       "content": "some cool content 2"
    };

index.add(document1);
index.add(document2);

var results = index.search("cool");
for (var i=0;i<results.length;i++) {
	var result = results[i];
    response.println("[Found for 'cool']: " + result.id);
}

results = index.search("1");
for (var i=0;i<results.length;i++) {
	var result = results[i];
    response.println("[Found for '1']: " + result.id);
}

results = index.search("2");
for (var i=0;i<results.length;i++) {
	var result = results[i];
    response.println("[Found for '2']: " + result.id);
}

index.clear();

response.flush();
response.close();
<|endoftext|>


<commit_before>import React, { Component, StyleSheet, View, Text, TouchableHighlight } from 'react-native';

export default class CustomCell extends Component {
  render() {
    const {title, cellstyle, isDisabled, accessory} = this.props || {
      cellstyle: 'Basic',
      isDisabled: 'false',
      accessory: ''
    }
    const isPressable = this.props.onPress ? true : false;

    let renderCell = () => {
      return(
        <View style={styles.cellcontainer}>
          <View style={styles.cell}>
            <Text style={isDisabled ? [...{}, styles.cell_title__disabled, styles.cell_title] : styles.cell_title}>{title}</Text>
            <View style={styles.cell_arrow}></View>
          </View>
        </View>
        )
    }

    if(isPressable && !isDisabled) {
        return(
          <TouchableHighlight onPress={this.props.onPress}>
            {renderCell()}
          </TouchableHighlight>
        )
      }
      return (<View>{renderCell()}</View>)

  }
}

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
    flexDirection: 'row'
  },

  'cell_arrow': {
    width: 10,
    height: 10,
    backgroundColor: 'transparent',
    borderTopWidth: 1.5,
    borderRightWidth: 1.5,
    borderColor: '#c7c7cc',
    transform: [{
      rotate: '45deg'
    }]
  }

});<commit_msg>remove custom cell component<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {
  const OptionsPage = options.OptionsPage;

  // The unique ID of the loaded credit card.
  var uniqueID;

  /**
   * AutoFillEditCreditCardOverlay class
   * Encapsulated handling of the 'Add Page' overlay page.
   * @class
   */
  function AutoFillEditCreditCardOverlay() {
    OptionsPage.call(this, 'autoFillEditCreditCardOverlay',
                     templateData.autoFillEditCreditCardTitle,
                     'autoFillEditCreditCardOverlay');
  }

  cr.addSingletonGetter(AutoFillEditCreditCardOverlay);

  AutoFillEditCreditCardOverlay.prototype = {
    __proto__: OptionsPage.prototype,

    /**
     * Initializes the page.
     */
    initializePage: function() {
      OptionsPage.prototype.initializePage.call(this);

      var self = this;
      $('autoFillEditCreditCardCancelButton').onclick = function(event) {
        self.dismissOverlay_();
      }
      $('autoFillEditCreditCardApplyButton').onclick = function(event) {
        self.saveCreditCard_();
        self.dismissOverlay_();
      }

      self.uniqueID = 0;
      self.clearInputFields_();
      self.connectInputEvents_();
      self.setDefaultSelectOptions_();
    },

    /**
     * Clears any uncommitted input, and dismisses the overlay.
     * @private
     */
    dismissOverlay_: function() {
      this.clearInputFields_();
      this.uniqueID = 0;
      OptionsPage.clearOverlays();
    },

    /**
     * Aggregates the values in the input fields into an array and sends the
     * array to the AutoFill handler.
     * @private
     */
    saveCreditCard_: function() {
      var creditCard = new Array(5);
      creditCard[0] = String(this.uniqueID);
      creditCard[1] = $('nameOnCard').value;
      creditCard[2] = $('creditCardNumber').value;
      creditCard[3] = $('expirationMonth').value;
      creditCard[4] = $('expirationYear').value;

      chrome.send('updateCreditCard', creditCard);
    },

    /**
     * Connects each input field to the inputFieldChanged_() method that enables
     * or disables the 'Ok' button based on whether all the fields are empty or
     * not.
     * @private
     */
    connectInputEvents_: function() {
      var self = this;
      $('nameOnCard').oninput = $('creditCardNumber').oninput =
      $('expirationMonth').onchange = $('expirationYear').onchange =
      // TODO(isherman): What should the indentation of this line be?
      function(event) {
        self.inputFieldChanged_();
      }
    },

    /**
     * Checks the values of each of the input fields and disables the 'Ok'
     * button if all of the fields are empty.
     * @private
     */
    inputFieldChanged_: function() {
      var disabled = !$('nameOnCard').value && !$('creditCardNumber').value;
      $('autoFillEditCreditCardApplyButton').disabled = disabled;
    },

    /**
     * Sets the default values of the options in the 'Expiration date' select
     * controls.
     * @private
     */
    setDefaultSelectOptions_: function() {
      // Set the 'Expiration month' default options.
      var expirationMonth = $('expirationMonth');
      for (var i = 1; i <= 12; ++i) {
        var text;
        if (i < 10)
          text = '0' + i;
        else
          text = i;

        var option = document.createElement('option');
        option.text = text;
        option.value = text;
        expirationMonth.add(option, null);
      }

      // Set the 'Expiration year' default options.
      var expirationYear = $('expirationYear');
      var date = new Date();
      var year = parseInt(date.getFullYear());
      for (var i = 0; i < 10; ++i) {
        var text = year + i;
        var option = document.createElement('option');
        option.text = text;
        option.value = text;
        expirationYear.add(option, null);
      }
    },

    /**
     * Clears the value of each input field.
     * @private
     */
    clearInputFields_: function() {
      $('nameOnCard').value = '';
      $('creditCardNumber').value = '';
      $('expirationMonth').selectedIndex = 0;
      $('expirationYear').selectedIndex = 0;
    },

    /**
     * Sets the value of each input field according to |creditCard|
     * @private
     */
    setInputFields_: function(creditCard) {
      $('nameOnCard').value = creditCard['nameOnCard'];
      $('creditCardNumber').value = creditCard['creditCardNumber'];

      // The options for the year select control may be out-dated at this point,
      // e.g. the user opened the options page before midnight on New Year's Eve
      // and then loaded a credit card profile to edit in the new year, so
      // reload the select options just to be safe.
      this.setDefaultSelectOptions_();

      var idx = parseInt(creditCard['expirationMonth'], 10);
      $('expirationMonth').selectedIndex = idx - 1;

      expYear = creditCard['expirationYear'];
      var date = new Date();
      var year = parseInt(date.getFullYear());
      for (var i = 0; i < 10; ++i) {
        var text = year + i;
        if (expYear == String(text))
          $('expirationYear').selectedIndex = i;
      }
    },

    /**
     * Loads the credit card data from |creditCard|, sets the input fields based
     * on this data and stores the unique ID of the credit card.
     * @private
     */
    loadCreditCard_: function(creditCard) {
      this.setInputFields_(creditCard);
      this.inputFieldChanged_();
      this.uniqueID = creditCard['uniqueID'];
    },
  };

  AutoFillEditCreditCardOverlay.clearInputFields = function(title) {
    AutoFillEditCreditCardOverlay.getInstance().clearInputFields_();
  };

  AutoFillEditCreditCardOverlay.loadCreditCard = function(creditCard) {
    AutoFillEditCreditCardOverlay.getInstance().loadCreditCard_(creditCard);
  };

  AutoFillEditCreditCardOverlay.setTitle = function(title) {
    $('autoFillCreditCardTitle').textContent = title;
  };

  // Export
  return {
    AutoFillEditCreditCardOverlay: AutoFillEditCreditCardOverlay
  };

});
<commit_msg>DOMUI: Clear the credit card select options when setting the default select options. This is a speculative fix for a bug where the dates are added twice.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {
  const OptionsPage = options.OptionsPage;

  // The unique ID of the loaded credit card.
  var uniqueID;

  /**
   * AutoFillEditCreditCardOverlay class
   * Encapsulated handling of the 'Add Page' overlay page.
   * @class
   */
  function AutoFillEditCreditCardOverlay() {
    OptionsPage.call(this, 'autoFillEditCreditCardOverlay',
                     templateData.autoFillEditCreditCardTitle,
                     'autoFillEditCreditCardOverlay');
  }

  cr.addSingletonGetter(AutoFillEditCreditCardOverlay);

  AutoFillEditCreditCardOverlay.prototype = {
    __proto__: OptionsPage.prototype,

    /**
     * Initializes the page.
     */
    initializePage: function() {
      OptionsPage.prototype.initializePage.call(this);

      var self = this;
      $('autoFillEditCreditCardCancelButton').onclick = function(event) {
        self.dismissOverlay_();
      }
      $('autoFillEditCreditCardApplyButton').onclick = function(event) {
        self.saveCreditCard_();
        self.dismissOverlay_();
      }

      self.uniqueID = 0;
      self.clearInputFields_();
      self.connectInputEvents_();
      self.setDefaultSelectOptions_();
    },

    /**
     * Clears any uncommitted input, and dismisses the overlay.
     * @private
     */
    dismissOverlay_: function() {
      this.clearInputFields_();
      this.uniqueID = 0;
      OptionsPage.clearOverlays();
    },

    /**
     * Aggregates the values in the input fields into an array and sends the
     * array to the AutoFill handler.
     * @private
     */
    saveCreditCard_: function() {
      var creditCard = new Array(5);
      creditCard[0] = String(this.uniqueID);
      creditCard[1] = $('nameOnCard').value;
      creditCard[2] = $('creditCardNumber').value;
      creditCard[3] = $('expirationMonth').value;
      creditCard[4] = $('expirationYear').value;

      chrome.send('updateCreditCard', creditCard);
    },

    /**
     * Connects each input field to the inputFieldChanged_() method that enables
     * or disables the 'Ok' button based on whether all the fields are empty or
     * not.
     * @private
     */
    connectInputEvents_: function() {
      var self = this;
      $('nameOnCard').oninput = $('creditCardNumber').oninput =
      $('expirationMonth').onchange = $('expirationYear').onchange =
      // TODO(isherman): What should the indentation of this line be?
      function(event) {
        self.inputFieldChanged_();
      }
    },

    /**
     * Checks the values of each of the input fields and disables the 'Ok'
     * button if all of the fields are empty.
     * @private
     */
    inputFieldChanged_: function() {
      var disabled = !$('nameOnCard').value && !$('creditCardNumber').value;
      $('autoFillEditCreditCardApplyButton').disabled = disabled;
    },

    /**
     * Sets the default values of the options in the 'Expiration date' select
     * controls.
     * @private
     */
    setDefaultSelectOptions_: function() {
      // Set the 'Expiration month' default options.
      var expirationMonth = $('expirationMonth');
      expirationMonth.options.length = 0;
      for (var i = 1; i <= 12; ++i) {
        var text;
        if (i < 10)
          text = '0' + i;
        else
          text = i;

        var option = document.createElement('option');
        option.text = text;
        option.value = text;
        expirationMonth.add(option, null);
      }

      // Set the 'Expiration year' default options.
      var expirationYear = $('expirationYear');
      expirationYear.options.length = 0;

      var date = new Date();
      var year = parseInt(date.getFullYear());
      for (var i = 0; i < 10; ++i) {
        var text = year + i;
        var option = document.createElement('option');
        option.text = text;
        option.value = text;
        expirationYear.add(option, null);
      }
    },

    /**
     * Clears the value of each input field.
     * @private
     */
    clearInputFields_: function() {
      $('nameOnCard').value = '';
      $('creditCardNumber').value = '';
      $('expirationMonth').selectedIndex = 0;
      $('expirationYear').selectedIndex = 0;
    },

    /**
     * Sets the value of each input field according to |creditCard|
     * @private
     */
    setInputFields_: function(creditCard) {
      $('nameOnCard').value = creditCard['nameOnCard'];
      $('creditCardNumber').value = creditCard['creditCardNumber'];

      // The options for the year select control may be out-dated at this point,
      // e.g. the user opened the options page before midnight on New Year's Eve
      // and then loaded a credit card profile to edit in the new year, so
      // reload the select options just to be safe.
      this.setDefaultSelectOptions_();

      var idx = parseInt(creditCard['expirationMonth'], 10);
      $('expirationMonth').selectedIndex = idx - 1;

      expYear = creditCard['expirationYear'];
      var date = new Date();
      var year = parseInt(date.getFullYear());
      for (var i = 0; i < 10; ++i) {
        var text = year + i;
        if (expYear == String(text))
          $('expirationYear').selectedIndex = i;
      }
    },

    /**
     * Loads the credit card data from |creditCard|, sets the input fields based
     * on this data and stores the unique ID of the credit card.
     * @private
     */
    loadCreditCard_: function(creditCard) {
      this.setInputFields_(creditCard);
      this.inputFieldChanged_();
      this.uniqueID = creditCard['uniqueID'];
    },
  };

  AutoFillEditCreditCardOverlay.clearInputFields = function(title) {
    AutoFillEditCreditCardOverlay.getInstance().clearInputFields_();
  };

  AutoFillEditCreditCardOverlay.loadCreditCard = function(creditCard) {
    AutoFillEditCreditCardOverlay.getInstance().loadCreditCard_(creditCard);
  };

  AutoFillEditCreditCardOverlay.setTitle = function(title) {
    $('autoFillCreditCardTitle').textContent = title;
  };

  // Export
  return {
    AutoFillEditCreditCardOverlay: AutoFillEditCreditCardOverlay
  };

});
<|endoftext|>


<commit_before>import React from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import moment from 'moment';
import { compose } from 'react-apollo';

// components
import AvatarIcon from '../profile/avatar/AvatarIcon';

// lib
import createRevisionMarkup from '../../lib/createRevisionMarkup';

// graphql
import { commentersQuery } from '../../graphql/methods/commenters';

const KeywordCommentList = (props) => {

	const { keywordComments } = props;

	if (!keywordComments || !keywordComments.length) {
		return (

					This tag has no comments associated with it yet.

		);
	}

	return (

			{props.keywordComments.map((comment, i) => {
				const selectedRevision = comment.revisions[comment.revisions.length - 1];
				const updated = selectedRevision.updated;
				const format = 'D MMMM YYYY';

				return (

<Link to={`/commentary?_id=${comment._id}`}>{selectedRevision.title}</Link>

								{comment.commenters.map((commenter, _i) => {
									const commenterRecord = commentersQuery.loading ? {} : commentersQuery.find(x =>
										x.slug === commenter.slug);

									if (!commenterRecord) {
										return null;
									}

									return (

												<Link to={`/commenters/${commenterRecord.slug}`}>
													{commenterRecord.name}
												</Link>

													{moment(updated).format(format)}

												<Link to={`/commenters/${commenterRecord.slug}`}>
													<AvatarIcon
														avatar={
															(commenterRecord && 'avatar' in commenterRecord) ?
															commenterRecord.avatar.src
															: null
														}
													/>
												</Link>

									);
								})}

				);
			})}

	);
};
KeywordCommentList.propTypes = {
	keywordComments: PropTypes.array,
};

export default compose(commentersQuery)(KeywordCommentList);
<commit_msg>fix kyeword bug<commit_after>import React from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import moment from 'moment';
import { compose } from 'react-apollo';

// components
import AvatarIcon from '../profile/avatar/AvatarIcon';

// lib
import createRevisionMarkup from '../../lib/createRevisionMarkup';

// graphql
import { commentersQuery } from '../../graphql/methods/commenters';

const KeywordCommentList = (props) => {

	const { keywordComments } = props;

	if (!keywordComments || !keywordComments.length) {
		return (

					This tag has no comments associated with it yet.

		);
	}

	return (

			{props.keywordComments.map((comment, i) => {
				const selectedRevision = comment.revisions[comment.revisions.length - 1];
				const updated = selectedRevision.updated;
				const format = 'D MMMM YYYY';

				return (

<Link to={`/commentary?_id=${comment._id}`}>{selectedRevision.title}</Link>

								{comment.commenters.map((commenter, _i) => {
									const commenterRecord = props.commentersQuery.loading ? {} : props.commentersQuery.commenters.find(x =>
										x.slug === commenter.slug);

									if (!commenterRecord) {
										return null;
									}

									return (

												<Link to={`/commenters/${commenterRecord.slug}`}>
													{commenterRecord.name}
												</Link>

													{moment(updated).format(format)}

												<Link to={`/commenters/${commenterRecord.slug}`}>
													<AvatarIcon
														avatar={
															(commenterRecord && 'avatar' in commenterRecord) ?
															commenterRecord.avatar.src
															: null
														}
													/>
												</Link>

									);
								})}

				);
			})}

	);
};
KeywordCommentList.propTypes = {
	keywordComments: PropTypes.array,
};

export default compose(commentersQuery)(KeywordCommentList);
<|endoftext|>


<commit_before>import React from 'react'
import enhanceWithClickOutside from 'react-click-outside'
import { withRouter } from 'next/router'

import { COLORS, EXPORT_SIZES } from '../lib/constants'
import Button from './Button'
import CopyButton from './CopyButton'
import WindowPointer from './WindowPointer'

import { toggle } from '../lib/util'

const toIFrame = url =>
  `

`

class ExportMenu extends React.PureComponent {
  state = {
    isVisible: false
  }

  toggle = () => this.setState(toggle('isVisible'))

  handleClickOutside = () => this.setState({ isVisible: false })

  handleInputChange = e => this.props.onChange(e.target.name, e.target.value)

  handleExportSizeChange = selectedSize => () => this.props.onChange('exportSize', selectedSize)

  handleExport = format => () => this.props.export(format)

  render() {
    const { exportSize, filename, router } = this.props
    const { isVisible } = this.state

    return (

        <Button
          selected={isVisible}
          className="exportButton"
          onClick={this.toggle}
          title="Export"
          color={COLORS.PURPLE}
        />

          <WindowPointer fromRight="28px" color={COLORS.PURPLE} />

            File name
            <input
              title="filename"
              placeholder="carbon"
              value={filename}
              name="filename"
              onChange={this.handleInputChange}
            />

              Size

                {EXPORT_SIZES.map(({ name }) => (
                  <button
                    key={name}
                    onClick={this.handleExportSizeChange(name)}
                    className={`size-button ${exportSize === name ? 'selected' : ''}`}
                  >
                    {name}
                  </button>
                ))}

            <button className="open-button" onClick={this.handleExport('open')}>
              Open ↗
            </button>
            <CopyButton text={toIFrame(router.asPath)}>
              {({ copied }) => (
                <button className="copy-button">{copied ? 'Copied!' : 'Copy Embed'}</button>
              )}
            </CopyButton>

              Save as

                <button onClick={this.handleExport('png')} className="save-button" id="export-png">
                  PNG
                </button>
                <button onClick={this.handleExport('svg')} className="save-button" id="export-svg">
                  SVG
                </button>

    )
  }
}

export default withRouter(enhanceWithClickOutside(ExportMenu))
<commit_msg>export-container -> export-menu-container"<commit_after>import React from 'react'
import enhanceWithClickOutside from 'react-click-outside'
import { withRouter } from 'next/router'

import { COLORS, EXPORT_SIZES } from '../lib/constants'
import Button from './Button'
import CopyButton from './CopyButton'
import WindowPointer from './WindowPointer'

import { toggle } from '../lib/util'

const toIFrame = url =>
  `

`

class ExportMenu extends React.PureComponent {
  state = {
    isVisible: false
  }

  toggle = () => this.setState(toggle('isVisible'))

  handleClickOutside = () => this.setState({ isVisible: false })

  handleInputChange = e => this.props.onChange(e.target.name, e.target.value)

  handleExportSizeChange = selectedSize => () => this.props.onChange('exportSize', selectedSize)

  handleExport = format => () => this.props.export(format)

  render() {
    const { exportSize, filename, router } = this.props
    const { isVisible } = this.state

    return (

        <Button
          selected={isVisible}
          className="exportButton"
          onClick={this.toggle}
          title="Export"
          color={COLORS.PURPLE}
        />

          <WindowPointer fromRight="28px" color={COLORS.PURPLE} />

            File name
            <input
              title="filename"
              placeholder="carbon"
              value={filename}
              name="filename"
              onChange={this.handleInputChange}
            />

              Size

                {EXPORT_SIZES.map(({ name }) => (
                  <button
                    key={name}
                    onClick={this.handleExportSizeChange(name)}
                    className={`size-button ${exportSize === name ? 'selected' : ''}`}
                  >
                    {name}
                  </button>
                ))}

            <button className="open-button" onClick={this.handleExport('open')}>
              Open ↗
            </button>
            <CopyButton text={toIFrame(router.asPath)}>
              {({ copied }) => (
                <button className="copy-button">{copied ? 'Copied!' : 'Copy Embed'}</button>
              )}
            </CopyButton>

              Save as

                <button onClick={this.handleExport('png')} className="save-button" id="export-png">
                  PNG
                </button>
                <button onClick={this.handleExport('svg')} className="save-button" id="export-svg">
                  SVG
                </button>

    )
  }
}

export default withRouter(enhanceWithClickOutside(ExportMenu))
<|endoftext|>


<commit_before>app.run([
  '$templateCache',
  function($templateCache) {

    // Create the component markup.
    $templateCache.put('formio/components/settings.html',
      '<form id="component-settings" novalidate>' +
        '
' +
          '
' +
            '<tabset>' +
              '<tab ng-repeat="view in formComponents[component.type].views" heading="{{ view.name }}"><ng-include src="view.template"></ng-include></tab>' +
            '</tabset>' +
          '
' +
          '
' +
            '
' +
              ' Help!' +
            '
' +
            '
' +
              '
Preview
' +
              '
' +
                '<formio-component component="component" data="data" formio="formio"></formio-component>' +
              '
' +
            '
' +
            '
' +
              '<button type="submit" class="btn btn-success" ng-click="saveSettings()">Save</button> ' +
              '<button type="button" class="btn btn-default" ng-click="cancelSettings()" ng-if="!component.isNew">Cancel</button> ' +
              '<button type="button" class="btn btn-danger" ng-click="removeComponent(component)">Remove</button>' +
            '
' +
          '
' +
        '
' +
      '</form>'
    );
  }
]);

app.constant('FORM_OPTIONS', {
  actions: [
    {
      name: 'submit',
      title: 'Submit'
    },
    {
      name: 'reset',
      title: 'Reset'
    }
  ],
  themes: [
    {
      name: 'default',
      title: 'Default'
    },
    {
      name: 'primary',
      title: 'Primary'
    },
    {
      name: 'info',
      title: 'Info'
    },
    {
      name: 'success',
      title: 'Succeess'
    },
    {
      name: 'danger',
      title: 'Danger'
    },
    {
      name: 'warning',
      title: 'Warning'
    }
  ],
  sizes: [
    {
      name: 'xs',
      title: 'Extra Small'
    },
    {
      name: 'sm',
      title: 'Small'
    },
    {
      name: 'md',
      title: 'Medium'
    },
    {
      name: 'lg',
      title: 'Large'
    }
  ]
});

/**
* These are component options that can be reused
* with the builder-option directive
* Valid properties: label, placeholder, tooltip, type
*/
app.constant('COMMON_OPTIONS', {
  label: {
    label: 'Label',
    placeholder: 'Field Label',
    tooltip: 'The label for this field that will appear next to it.'
  },
  placeholder: {
    label: 'Placeholder',
    placeholder: 'Placeholder',
    tooltip: 'The placeholder text that will appear when this field is empty.'
  },
  inputMask: {
    label: 'Input Mask',
    placeholder: 'Input Mask',
    tooltip: 'An input mask helps the user with input by ensuring a predefined format.

9: numeric
a: alphabetical
*: alphanumeric

Example telephone mask: (999) 999-9999

See the jquery.inputmask documentation for more information.'
  },
  tableView: {
    label: 'Table View',
    type: 'checkbox',
    tooltip: 'Shows this value within the table view of the submissions.'
  },
  prefix: {
    label: 'Prefix',
    placeholder: 'example \'$\', \'@\'',
    tooltip: 'The text to show before a field.'
  },
  suffix: {
    label: 'Suffix',
    placeholder: 'example \'$\', \'@\'',
    tooltip: 'The text to show after a field.'
  },
  multiple: {
    label: 'Multiple Values',
    type: 'checkbox',
    tooltip: 'Allows multiple values to be entered for this field.'
  },
  unique: {
    label: 'Unique',
    type: 'checkbox',
    tooltip: 'Makes sure the data submitted for this field is unique, and has not been submitted before.'
  },
  protected: {
    label: 'Protected',
    type: 'checkbox',
    tooltip: 'A protected field will not be returned when queried via API.'
  },
  persistent: {
    label: 'Persistent',
    type: 'checkbox',
    tooltip: 'A persistent field will be stored in database when the form is submitted.'
  },
  block: {
    label: 'Block',
    type: 'checkbox',
    tooltip: 'This control should span the full width of the bounding container.'
  },
  leftIcon: {
    label: 'Left Icon',
    placeholder: 'Enter icon classes',
    tooltip: 'This is the full icon class string to show the icon. Example: "glyphicon glyphicon-search" or "fa fa-plus"'
  },
  rightIcon: {
    label: 'Right Icon',
    placeholder: 'Enter icon classes',
    tooltip: 'This is the full icon class string to show the icon. Example: "glyphicon glyphicon-search" or "fa fa-plus"'
  },
  disableOnInvalid: {
    label: 'Disable on Form Invalid',
    type: 'checkbox',
    tooltip: 'This will disable this field if the form is invalid.'
  },
  'validate.required': {
    label: 'Required',
    type: 'checkbox',
    tooltip: 'A required field must be filled in before the form can be submitted.'
  },
  'validate.minLength': {
    label: 'Minimum Length',
    placeholder: 'Minimum Length',
    type: 'number',
    tooltip: 'The minimum length requirement this field must meet.'
  },
  'validate.maxLength': {
    label: 'Maximum Length',
    placeholder: 'Maximum Length',
    type: 'number',
    tooltip: 'The maximum length requirement this field must meet'
  },
  'validate.pattern': {
    label: 'Regular Expression Pattern',
    placeholder: 'Regular Expression Pattern',
    tooltip: 'The regular expression pattern test that the field value must pass before the form can be submitted.'
  }
});

// Common directives for editing component

/**
* This directive creates a field for tweaking component options.
* This needs at least a property attribute specifying what property
* of the component to bind to.
*
* If the property is defined in COMMON_OPTIONS above, it will automatically
* populate its label, placeholder, input type, and tooltip. If not, you may specify
* those via attributes (except for tooltip, which you can specify with the title attribute).
* The generated input will also carry over any other properties you specify on this directive.
*/
app.directive('formBuilderOption', ['COMMON_OPTIONS', function(COMMON_OPTIONS){
  return {
    restrict: 'E',
    require: 'property',
    priority: 2,
    replace: true,
    template: function(el, attrs) {
      var property = attrs.property;
      var label = attrs.label || (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].label) || '';
      var placeholder = (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].placeholder) || null;
      var type = (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].type) || 'text';
      var tooltip = (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].tooltip) || '';

      var input = angular.element('<input></input>');
      var inputAttrs = {
        id: property,
        name: property,
        type: type,
        'ng-model': 'component.' + property,
        placeholder: placeholder
      };
      // Pass through attributes from the directive to the input element
      angular.forEach(attrs.$attr, function(key) {
        inputAttrs[key] = attrs[key];
        // Allow specifying tooltip via title attr
        if(key.toLowerCase() === 'title') {
          tooltip = attrs[key];
        }
      });
      input.attr(inputAttrs);

      // Checkboxes have a slightly different layout
      if(inputAttrs.type.toLowerCase() === 'checkbox') {
        return '
' +
                '' +
                input.prop('outerHTML') +
                ' ' + label + '' +
              '
';
      }

      input.addClass('form-control');
      return '
' +
                '' + label + '' +
                input.prop('outerHTML') +
              '
';
    }
  };
}]);

/**
* A directive for a field to edit a component's key.
*/
app.directive('formBuilderOptionKey', function(){
  return {
    restrict: 'E',
    replace: true,
    template: function(el, attrs) {
      return '
' +
                'Property Name' +
                '<input type="text" class="form-control" id="key" name="key" ng-model="component.key" valid-api-key value="{{ component.key }}" ' +
                'ng-disabled="component.source" ng-blur="component.lockKey = true;" ' +
                  'ng-required>' +
                '
 ' +
                  'Using a dot in your Property Name will link this field to a field from a Resource. Doing this manually is not recommended because you will experience unexpected behavior if the Resource field is not found. If you wish to embed a Resource field in your form, use a component from the corresponding Resource Components category on the left.' +
                '
' +
              '
';
    },
    link: function($scope) {
      var suffixRegex = /(\d+)$/;
      $scope.$watch('component.key', function(newValue) {
        var valid = $scope.form.components.every(function(component) {
          if(component.key === newValue && component !== $scope.component) {
            return false;
          }
          return true;
        });
        if(valid) {
          return;
        }
        if(suffixRegex.test(newValue)) {
          newValue = newValue.replace(suffixRegex, function(suffix) { return Number(suffix) + 1; });
        }
        else {
          newValue += '2';
        }
        $scope.component.key = newValue;
      });

      $scope.shouldWarnAboutEmbedding = function() {
        return !$scope.component.source && $scope.component.key.indexOf('.') !== -1;
      };
    },
  };
});

/*
* Prevents user inputting invalid api key characters.
* Valid characters for an api key are alphanumeric and hyphens
*/
app.directive('validApiKey', function(){
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
      var invalidRegex = /^[^A-Za-z]*|[^A-Za-z0-9\-\.]*/g;
      ngModel.$parsers.push(function (inputValue) {
        var transformedInput = inputValue.replace(invalidRegex, '');
        if (transformedInput !== inputValue) {
          ngModel.$setViewValue(transformedInput);
          ngModel.$render();
        }
        return transformedInput;
     });
    }
  };
});

/**
* A directive for editing a component's custom validation.
*/
app.directive('formBuilderOptionCustomValidation', function(){
  return {
    restrict: 'E',
    replace: true,
    template: '
' +
                '
Custom Validation
' +
                '
' +
                  '<textarea class="form-control" rows="5" id="custom" name="custom" ng-model="component.validate.custom" placeholder="/*** Example Code ***/\nvalid = (input === 3) ? true : \'Must be 3\';">{{ component.validate.custom }}</textarea>' +
                  '
Enter custom validation code.
' +
                  '
You must assign the valid variable as either true or an error message if validation fails.
' +
                  '
The global variables input, component, and valid are provided.
' +
                  '
' +
                    '
' +
                      '' +
                        '<input type="checkbox" id="private" name="private" ng-model="component.validate.customPrivate" ng-checked="component.validate.customPrivate"> Secret Validation' +
                      '' +
                    '
' +
                    '
Check this if you wish to perform the validation ONLY on the server side. This keeps your validation logic private and secret.
' +
                  '
' +
                '
' +
              '
'
  };
});

/**
* A directive that provides a UI to add {value, label} objects to an array.
*/
app.directive('valueBuilder', function(){
  return {
    scope: {
      data: '=',
      label: '@',
      tooltipText: '@'
    },
    restrict: 'E', // E = Element, A = Attribute, C = Class, M = Comment
    template: '
' +
                '{{ label }}' +
                '
' +
                  '
' +
                    '
' +
                      'Value	' +
                      'Label	' +
                      '	' +
                    '
' +
                  '
' +
                  '
' +
                    '
' +
                      '<input type="text" class="form-control" ng-model="v.value" placeholder="Value"/>	' +
                      '<input type="text" class="form-control" ng-model="v.label" placeholder="Label"/>	' +
                      '<button type="button" class="btn btn-danger btn-xs" ng-click="removeValue($index)"></button>	' +
                    '
' +
                  '
' +
                '
' +
                '<button type="button" class="btn" ng-click="addValue()">Add Value</button>' +
                '
',
    replace: true,
    link: function($scope) {
      $scope.addValue = function() {
        $scope.data.push({
          value: '',
          label: ''
        });
      };
      $scope.removeValue = function(index) {
        $scope.data.splice(index, 1);
      };
      if($scope.data.length === 0) {
        $scope.addValue();
      }
    }
  };
});
<commit_msg>FA-431 Fix spelling of Succeess.<commit_after>app.run([
  '$templateCache',
  function($templateCache) {

    // Create the component markup.
    $templateCache.put('formio/components/settings.html',
      '<form id="component-settings" novalidate>' +
        '
' +
          '
' +
            '<tabset>' +
              '<tab ng-repeat="view in formComponents[component.type].views" heading="{{ view.name }}"><ng-include src="view.template"></ng-include></tab>' +
            '</tabset>' +
          '
' +
          '
' +
            '
' +
              ' Help!' +
            '
' +
            '
' +
              '
Preview
' +
              '
' +
                '<formio-component component="component" data="data" formio="formio"></formio-component>' +
              '
' +
            '
' +
            '
' +
              '<button type="submit" class="btn btn-success" ng-click="saveSettings()">Save</button> ' +
              '<button type="button" class="btn btn-default" ng-click="cancelSettings()" ng-if="!component.isNew">Cancel</button> ' +
              '<button type="button" class="btn btn-danger" ng-click="removeComponent(component)">Remove</button>' +
            '
' +
          '
' +
        '
' +
      '</form>'
    );
  }
]);

app.constant('FORM_OPTIONS', {
  actions: [
    {
      name: 'submit',
      title: 'Submit'
    },
    {
      name: 'reset',
      title: 'Reset'
    }
  ],
  themes: [
    {
      name: 'default',
      title: 'Default'
    },
    {
      name: 'primary',
      title: 'Primary'
    },
    {
      name: 'info',
      title: 'Info'
    },
    {
      name: 'success',
      title: 'Success'
    },
    {
      name: 'danger',
      title: 'Danger'
    },
    {
      name: 'warning',
      title: 'Warning'
    }
  ],
  sizes: [
    {
      name: 'xs',
      title: 'Extra Small'
    },
    {
      name: 'sm',
      title: 'Small'
    },
    {
      name: 'md',
      title: 'Medium'
    },
    {
      name: 'lg',
      title: 'Large'
    }
  ]
});

/**
* These are component options that can be reused
* with the builder-option directive
* Valid properties: label, placeholder, tooltip, type
*/
app.constant('COMMON_OPTIONS', {
  label: {
    label: 'Label',
    placeholder: 'Field Label',
    tooltip: 'The label for this field that will appear next to it.'
  },
  placeholder: {
    label: 'Placeholder',
    placeholder: 'Placeholder',
    tooltip: 'The placeholder text that will appear when this field is empty.'
  },
  inputMask: {
    label: 'Input Mask',
    placeholder: 'Input Mask',
    tooltip: 'An input mask helps the user with input by ensuring a predefined format.

9: numeric
a: alphabetical
*: alphanumeric

Example telephone mask: (999) 999-9999

See the jquery.inputmask documentation for more information.'
  },
  tableView: {
    label: 'Table View',
    type: 'checkbox',
    tooltip: 'Shows this value within the table view of the submissions.'
  },
  prefix: {
    label: 'Prefix',
    placeholder: 'example \'$\', \'@\'',
    tooltip: 'The text to show before a field.'
  },
  suffix: {
    label: 'Suffix',
    placeholder: 'example \'$\', \'@\'',
    tooltip: 'The text to show after a field.'
  },
  multiple: {
    label: 'Multiple Values',
    type: 'checkbox',
    tooltip: 'Allows multiple values to be entered for this field.'
  },
  unique: {
    label: 'Unique',
    type: 'checkbox',
    tooltip: 'Makes sure the data submitted for this field is unique, and has not been submitted before.'
  },
  protected: {
    label: 'Protected',
    type: 'checkbox',
    tooltip: 'A protected field will not be returned when queried via API.'
  },
  persistent: {
    label: 'Persistent',
    type: 'checkbox',
    tooltip: 'A persistent field will be stored in database when the form is submitted.'
  },
  block: {
    label: 'Block',
    type: 'checkbox',
    tooltip: 'This control should span the full width of the bounding container.'
  },
  leftIcon: {
    label: 'Left Icon',
    placeholder: 'Enter icon classes',
    tooltip: 'This is the full icon class string to show the icon. Example: "glyphicon glyphicon-search" or "fa fa-plus"'
  },
  rightIcon: {
    label: 'Right Icon',
    placeholder: 'Enter icon classes',
    tooltip: 'This is the full icon class string to show the icon. Example: "glyphicon glyphicon-search" or "fa fa-plus"'
  },
  disableOnInvalid: {
    label: 'Disable on Form Invalid',
    type: 'checkbox',
    tooltip: 'This will disable this field if the form is invalid.'
  },
  'validate.required': {
    label: 'Required',
    type: 'checkbox',
    tooltip: 'A required field must be filled in before the form can be submitted.'
  },
  'validate.minLength': {
    label: 'Minimum Length',
    placeholder: 'Minimum Length',
    type: 'number',
    tooltip: 'The minimum length requirement this field must meet.'
  },
  'validate.maxLength': {
    label: 'Maximum Length',
    placeholder: 'Maximum Length',
    type: 'number',
    tooltip: 'The maximum length requirement this field must meet'
  },
  'validate.pattern': {
    label: 'Regular Expression Pattern',
    placeholder: 'Regular Expression Pattern',
    tooltip: 'The regular expression pattern test that the field value must pass before the form can be submitted.'
  }
});

// Common directives for editing component

/**
* This directive creates a field for tweaking component options.
* This needs at least a property attribute specifying what property
* of the component to bind to.
*
* If the property is defined in COMMON_OPTIONS above, it will automatically
* populate its label, placeholder, input type, and tooltip. If not, you may specify
* those via attributes (except for tooltip, which you can specify with the title attribute).
* The generated input will also carry over any other properties you specify on this directive.
*/
app.directive('formBuilderOption', ['COMMON_OPTIONS', function(COMMON_OPTIONS){
  return {
    restrict: 'E',
    require: 'property',
    priority: 2,
    replace: true,
    template: function(el, attrs) {
      var property = attrs.property;
      var label = attrs.label || (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].label) || '';
      var placeholder = (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].placeholder) || null;
      var type = (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].type) || 'text';
      var tooltip = (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].tooltip) || '';

      var input = angular.element('<input></input>');
      var inputAttrs = {
        id: property,
        name: property,
        type: type,
        'ng-model': 'component.' + property,
        placeholder: placeholder
      };
      // Pass through attributes from the directive to the input element
      angular.forEach(attrs.$attr, function(key) {
        inputAttrs[key] = attrs[key];
        // Allow specifying tooltip via title attr
        if(key.toLowerCase() === 'title') {
          tooltip = attrs[key];
        }
      });
      input.attr(inputAttrs);

      // Checkboxes have a slightly different layout
      if(inputAttrs.type.toLowerCase() === 'checkbox') {
        return '
' +
                '' +
                input.prop('outerHTML') +
                ' ' + label + '' +
              '
';
      }

      input.addClass('form-control');
      return '
' +
                '' + label + '' +
                input.prop('outerHTML') +
              '
';
    }
  };
}]);

/**
* A directive for a field to edit a component's key.
*/
app.directive('formBuilderOptionKey', function(){
  return {
    restrict: 'E',
    replace: true,
    template: function(el, attrs) {
      return '
' +
                'Property Name' +
                '<input type="text" class="form-control" id="key" name="key" ng-model="component.key" valid-api-key value="{{ component.key }}" ' +
                'ng-disabled="component.source" ng-blur="component.lockKey = true;" ' +
                  'ng-required>' +
                '
 ' +
                  'Using a dot in your Property Name will link this field to a field from a Resource. Doing this manually is not recommended because you will experience unexpected behavior if the Resource field is not found. If you wish to embed a Resource field in your form, use a component from the corresponding Resource Components category on the left.' +
                '
' +
              '
';
    },
    link: function($scope) {
      var suffixRegex = /(\d+)$/;
      $scope.$watch('component.key', function(newValue) {
        var valid = $scope.form.components.every(function(component) {
          if(component.key === newValue && component !== $scope.component) {
            return false;
          }
          return true;
        });
        if(valid) {
          return;
        }
        if(suffixRegex.test(newValue)) {
          newValue = newValue.replace(suffixRegex, function(suffix) { return Number(suffix) + 1; });
        }
        else {
          newValue += '2';
        }
        $scope.component.key = newValue;
      });

      $scope.shouldWarnAboutEmbedding = function() {
        return !$scope.component.source && $scope.component.key.indexOf('.') !== -1;
      };
    },
  };
});

/*
* Prevents user inputting invalid api key characters.
* Valid characters for an api key are alphanumeric and hyphens
*/
app.directive('validApiKey', function(){
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
      var invalidRegex = /^[^A-Za-z]*|[^A-Za-z0-9\-\.]*/g;
      ngModel.$parsers.push(function (inputValue) {
        var transformedInput = inputValue.replace(invalidRegex, '');
        if (transformedInput !== inputValue) {
          ngModel.$setViewValue(transformedInput);
          ngModel.$render();
        }
        return transformedInput;
     });
    }
  };
});

/**
* A directive for editing a component's custom validation.
*/
app.directive('formBuilderOptionCustomValidation', function(){
  return {
    restrict: 'E',
    replace: true,
    template: '
' +
                '
Custom Validation
' +
                '
' +
                  '<textarea class="form-control" rows="5" id="custom" name="custom" ng-model="component.validate.custom" placeholder="/*** Example Code ***/\nvalid = (input === 3) ? true : \'Must be 3\';">{{ component.validate.custom }}</textarea>' +
                  '
Enter custom validation code.
' +
                  '
You must assign the valid variable as either true or an error message if validation fails.
' +
                  '
The global variables input, component, and valid are provided.
' +
                  '
' +
                    '
' +
                      '' +
                        '<input type="checkbox" id="private" name="private" ng-model="component.validate.customPrivate" ng-checked="component.validate.customPrivate"> Secret Validation' +
                      '' +
                    '
' +
                    '
Check this if you wish to perform the validation ONLY on the server side. This keeps your validation logic private and secret.
' +
                  '
' +
                '
' +
              '
'
  };
});

/**
* A directive that provides a UI to add {value, label} objects to an array.
*/
app.directive('valueBuilder', function(){
  return {
    scope: {
      data: '=',
      label: '@',
      tooltipText: '@'
    },
    restrict: 'E', // E = Element, A = Attribute, C = Class, M = Comment
    template: '
' +
                '{{ label }}' +
                '
' +
                  '
' +
                    '
' +
                      'Value	' +
                      'Label	' +
                      '	' +
                    '
' +
                  '
' +
                  '
' +
                    '
' +
                      '<input type="text" class="form-control" ng-model="v.value" placeholder="Value"/>	' +
                      '<input type="text" class="form-control" ng-model="v.label" placeholder="Label"/>	' +
                      '<button type="button" class="btn btn-danger btn-xs" ng-click="removeValue($index)"></button>	' +
                    '
' +
                  '
' +
                '
' +
                '<button type="button" class="btn" ng-click="addValue()">Add Value</button>' +
                '
',
    replace: true,
    link: function($scope) {
      $scope.addValue = function() {
        $scope.data.push({
          value: '',
          label: ''
        });
      };
      $scope.removeValue = function(index) {
        $scope.data.splice(index, 1);
      };
      if($scope.data.length === 0) {
        $scope.addValue();
      }
    }
  };
});
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '../styles/withStyles';
import { capitalize } from '../utils/helpers';
import { darken, fade, lighten } from '../styles/colorManipulator';

export const styles = theme => ({
  /* Styles applied to the root element. */
  root: {
    display: 'table-cell',
    verticalAlign: 'inherit',
    // Workaround for a rendering bug with spanned columns in Chrome 62.0.
    // Removes the alpha (sets it to 1), and lightens or darkens the theme color.
    borderBottom: `1px solid
    ${
      theme.palette.type === 'light'
        ? lighten(fade(theme.palette.divider, 1), 0.88)
        : darken(fade(theme.palette.divider, 1), 0.8)
    }`,
    textAlign: 'left',
    padding: '4px 56px 4px 24px',
    '&:last-child': {
      paddingRight: 24,
    },
  },
  /* Styles applied to the root element if `variant="head"` or `context.table.head`. */
  head: {
    color: theme.palette.text.secondary,
    fontSize: theme.typography.pxToRem(12),
    fontWeight: theme.typography.fontWeightMedium,
  },
  /* Styles applied to the root element if `variant="body"` or `context.table.body`. */
  body: {
    color: theme.palette.text.primary,
    fontSize: theme.typography.pxToRem(13),
    fontWeight: theme.typography.fontWeightRegular,
  },
  /* Styles applied to the root element if `variant="footer"` or `context.table.footer`. */
  footer: {
    borderBottom: 0,
    color: theme.palette.text.secondary,
    fontSize: theme.typography.pxToRem(12),
  },
  /* Styles applied to the root element if `numeric={true}`. */
  numeric: {
    textAlign: 'right',
    flexDirection: 'row-reverse', // can be dynamically inherited at runtime by contents
  },
  /* Styles applied to the root element if `padding="dense"`. */
  paddingDense: {
    paddingRight: 24,
  },
  /* Styles applied to the root element if `padding="checkbox"`. */
  paddingCheckbox: {
    padding: '0 12px',
    '&:last-child': {
      paddingRight: 12,
    },
  },
  /* Styles applied to the root element if `padding="none"`. */
  paddingNone: {
    padding: 0,
    '&:last-child': {
      padding: 0,
    },
  },
});

function TableCell(props, context) {
  const {
    children,
    classes,
    className: classNameProp,
    component,
    sortDirection,
    numeric,
    padding: paddingProp,
    scope: scopeProp,
    variant,
    ...other
  } = props;

  const { table, tablelvl2 } = context;
  let Component;
  if (component) {
    Component = component;
  } else {
    Component = tablelvl2 && tablelvl2.variant === 'head' ? 'th' : 'td';
  }

  let scope = scopeProp;
  if (!scope && tablelvl2 && tablelvl2.variant === 'head') {
    scope = 'col';
  }
  const padding = paddingProp || (table && table.padding ? table.padding : 'default');

  const className = classNames(
    classes.root,
    {
      [classes.head]: variant ? variant === 'head' : tablelvl2 && tablelvl2.variant === 'head',
      [classes.body]: variant ? variant === 'body' : tablelvl2 && tablelvl2.variant === 'body',
      [classes.footer]: variant
        ? variant === 'footer'
        : tablelvl2 && tablelvl2.variant === 'footer',
      [classes.numeric]: numeric,
      [classes[`padding${capitalize(padding)}`]]: padding !== 'default',
    },
    classNameProp,
  );

  let ariaSort = null;
  if (sortDirection) {
    ariaSort = sortDirection === 'asc' ? 'ascending' : 'descending';
  }

  return (
    <Component className={className} aria-sort={ariaSort} scope={scope} {...other}>
      {children}
    </Component>
  );
}

TableCell.propTypes = {
  /**
   * The table cell contents.
   */
  children: PropTypes.node,
  /**
   * Override or extend the styles applied to the component.
   * See [CSS API](#css-api) below for more details.
   */
  classes: PropTypes.object.isRequired,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * The component used for the root node.
   * Either a string to use a DOM element or a component.
   */
  component: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.object]),
  /**
   * If `true`, content will align to the right.
   */
  numeric: PropTypes.bool,
  /**
   * Sets the padding applied to the cell.
   * By default, the Table parent component set the value.
   */
  padding: PropTypes.oneOf(['default', 'checkbox', 'dense', 'none']),
  /**
   * Set scope attribute.
   */
  scope: PropTypes.string,
  /**
   * Set aria-sort direction.
   */
  sortDirection: PropTypes.oneOf(['asc', 'desc', false]),
  /**
   * Specify the cell type.
   * By default, the TableHead, TableBody or TableFooter parent component set the value.
   */
  variant: PropTypes.oneOf(['head', 'body', 'footer']),
};

TableCell.defaultProps = {
  numeric: false,
};

TableCell.contextTypes = {
  table: PropTypes.object,
  tablelvl2: PropTypes.object,
};

export default withStyles(styles, { name: 'MuiTableCell' })(TableCell);
<commit_msg>[Table] Change divider color in dark theme (#13395)<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '../styles/withStyles';
import { capitalize } from '../utils/helpers';
import { darken, fade, lighten } from '../styles/colorManipulator';

export const styles = theme => ({
  /* Styles applied to the root element. */
  root: {
    display: 'table-cell',
    verticalAlign: 'inherit',
    // Workaround for a rendering bug with spanned columns in Chrome 62.0.
    // Removes the alpha (sets it to 1), and lightens or darkens the theme color.
    borderBottom: `1px solid
    ${
      theme.palette.type === 'light'
        ? lighten(fade(theme.palette.divider, 1), 0.88)
        : darken(fade(theme.palette.divider, 1), 0.68)
    }`,
    textAlign: 'left',
    padding: '4px 56px 4px 24px',
    '&:last-child': {
      paddingRight: 24,
    },
  },
  /* Styles applied to the root element if `variant="head"` or `context.table.head`. */
  head: {
    color: theme.palette.text.secondary,
    fontSize: theme.typography.pxToRem(12),
    fontWeight: theme.typography.fontWeightMedium,
  },
  /* Styles applied to the root element if `variant="body"` or `context.table.body`. */
  body: {
    color: theme.palette.text.primary,
    fontSize: theme.typography.pxToRem(13),
    fontWeight: theme.typography.fontWeightRegular,
  },
  /* Styles applied to the root element if `variant="footer"` or `context.table.footer`. */
  footer: {
    borderBottom: 0,
    color: theme.palette.text.secondary,
    fontSize: theme.typography.pxToRem(12),
  },
  /* Styles applied to the root element if `numeric={true}`. */
  numeric: {
    textAlign: 'right',
    flexDirection: 'row-reverse', // can be dynamically inherited at runtime by contents
  },
  /* Styles applied to the root element if `padding="dense"`. */
  paddingDense: {
    paddingRight: 24,
  },
  /* Styles applied to the root element if `padding="checkbox"`. */
  paddingCheckbox: {
    padding: '0 12px',
    '&:last-child': {
      paddingRight: 12,
    },
  },
  /* Styles applied to the root element if `padding="none"`. */
  paddingNone: {
    padding: 0,
    '&:last-child': {
      padding: 0,
    },
  },
});

function TableCell(props, context) {
  const {
    children,
    classes,
    className: classNameProp,
    component,
    sortDirection,
    numeric,
    padding: paddingProp,
    scope: scopeProp,
    variant,
    ...other
  } = props;

  const { table, tablelvl2 } = context;
  let Component;
  if (component) {
    Component = component;
  } else {
    Component = tablelvl2 && tablelvl2.variant === 'head' ? 'th' : 'td';
  }

  let scope = scopeProp;
  if (!scope && tablelvl2 && tablelvl2.variant === 'head') {
    scope = 'col';
  }
  const padding = paddingProp || (table && table.padding ? table.padding : 'default');

  const className = classNames(
    classes.root,
    {
      [classes.head]: variant ? variant === 'head' : tablelvl2 && tablelvl2.variant === 'head',
      [classes.body]: variant ? variant === 'body' : tablelvl2 && tablelvl2.variant === 'body',
      [classes.footer]: variant
        ? variant === 'footer'
        : tablelvl2 && tablelvl2.variant === 'footer',
      [classes.numeric]: numeric,
      [classes[`padding${capitalize(padding)}`]]: padding !== 'default',
    },
    classNameProp,
  );

  let ariaSort = null;
  if (sortDirection) {
    ariaSort = sortDirection === 'asc' ? 'ascending' : 'descending';
  }

  return (
    <Component className={className} aria-sort={ariaSort} scope={scope} {...other}>
      {children}
    </Component>
  );
}

TableCell.propTypes = {
  /**
   * The table cell contents.
   */
  children: PropTypes.node,
  /**
   * Override or extend the styles applied to the component.
   * See [CSS API](#css-api) below for more details.
   */
  classes: PropTypes.object.isRequired,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * The component used for the root node.
   * Either a string to use a DOM element or a component.
   */
  component: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.object]),
  /**
   * If `true`, content will align to the right.
   */
  numeric: PropTypes.bool,
  /**
   * Sets the padding applied to the cell.
   * By default, the Table parent component set the value.
   */
  padding: PropTypes.oneOf(['default', 'checkbox', 'dense', 'none']),
  /**
   * Set scope attribute.
   */
  scope: PropTypes.string,
  /**
   * Set aria-sort direction.
   */
  sortDirection: PropTypes.oneOf(['asc', 'desc', false]),
  /**
   * Specify the cell type.
   * By default, the TableHead, TableBody or TableFooter parent component set the value.
   */
  variant: PropTypes.oneOf(['head', 'body', 'footer']),
};

TableCell.defaultProps = {
  numeric: false,
};

TableCell.contextTypes = {
  table: PropTypes.object,
  tablelvl2: PropTypes.object,
};

export default withStyles(styles, { name: 'MuiTableCell' })(TableCell);
<|endoftext|>