<commit_before>//
// This is our "Enter OPAT" flow controller
//
controllers.controller(
    'OPATReferralCtrl',
    function($scope, $modalInstance, $modal, $rootScope,
             schema, options,
             Episode){

        $scope.model = {
            hospital_number : null
        }
        $scope.patient = null;

        //
        // When we've created an episode with this flow, tag it to the correct
        // teams and then kill the modal.
        //
        $scope.tag_and_close = function(episode){
            if(!episode.newItem){
                episode = new Episode(episode, schema);
            };
            if(!episode.tagging[0].makeCopy){
                episode.tagging[0] = episode.newItem('tagging');
            }
            var teams = episode.tagging[0].makeCopy();
            var location = episode.location[0].makeCopy();
            teams.opat = true;
            teams.opat_referrals = true;
            location.category = 'OPAT';

            //
            // Pre fill some tests:
            //
            var mrsa = episode.newItem('microbiology_test');
            var vte = episode.newItem('microbiology_test');

            // TODO - these are promises - the API is nicer than this !
            episode.tagging[0].save(teams).then(function(){
                episode.location[0].save(location).then(function(){
                    mrsa.save({test: 'MRSA PCR'}).then(function(mrsa_test){
                        vte.save({test: 'VTE Assessment'}).then(function(){
                            episode.active = true;
                            $modalInstance.close(episode);
                        });
                    });
                })
            });
        };

        //
        // We have an initial hospital number - we can now figure out whether to
        // Add or pull over.
        //
        $scope.find_by_hospital_number = function(){
            Episode.findByHospitalNumber(
                $scope.model.hospital_number,
                {
                    newPatient: $scope.new_patient,
                    newForPatient: $scope.new_for_patient,
                    error: function(){
			            // This shouldn't happen, but we should probably handle it better
			            alert('ERROR: More than one patient found with hospital number');
                        $modalInstance.close(null)
                    }
                }
            );
        };

        //
        // Create a new patient
        //
        $scope.new_patient = function(result){
			// There is no patient with this hospital number
			// Show user the form for creating a new episode,
            // with the hospital number pre-populated
			modal = $modal.open({
				templateUrl: '/templates/modals/opat/add_episode.html/',
				controller: 'AddEpisodeCtrl',
				resolve: {
					schema: function() { return schema; },
					options: function() { return options; },
					demographics: function() {
						return { hospital_number: $scope.hospital_number }
					}
				}
			}).result.then(function(result) {
				// The user has created the episode, or cancelled
                if(result){ // We made an episode!
                    $scope.tag_and_close(result);
                }else{
				    $modalInstance.close(result);
                }
			});
        };

        //
        // Create a new episode for an existing patient
        //
        $scope.new_for_patient = function(patient){
            if(patient.active_episode_id && _.keys(patient.episodes).length > 0){
                // Offer to import the data from this episode.
				for (var eix in patient.episodes) {
					patient.episodes[eix] = new Episode(patient.episodes[eix], schema);
				};
				modal = $modal.open({
					templateUrl: '/templates/modals/copy_to_category.html/',
					controller: 'CopyToCategoryCtrl',
					resolve: {
                        category: function() { return 'OPAT' },
						patient: function() { return patient; },
					}
				}).result.then(
                    function(result) {
                        if(!_.isString(result)){
                            $scope.tag_and_close(result);
                            return
                        };
					    if (result == 'open-new') {
						    // User has chosen to open a new episode
                            $scope.add_for_patient(patient);
					    } else {
						    // User has chosen to reopen an episode, or cancelled
						    $modalInstance.close(result);
					    };
				    },
                    function(result){ $modalInstance.close(result); });
            }else{
                $scope.add_for_patient(patient);
            };
        };

        //
        // Add a new episode for an existing patient. Pre-fill the relevant demographics
        //
        $scope.add_for_patient = function(patient){
            var demographics = patient.demographics[0];
            if(demographics.date_of_birth){
                var dob = moment(demographics.date_of_birth, 'YYYY-MM-DD')
                    .format('DD/MM/YYYY');
				demographics.date_of_birth = dob;
            }
			modal = $modal.open({
				templateUrl: '/templates/modals/opat/add_episode.html/',
				controller: 'AddEpisodeCtrl',
				resolve: {
					schema: function() { return schema; },
					options: function() { return options; },
					demographics: function() { return demographics; }
				}
			}).result.then(function(result) {
				// The user has created the episode, or cancelled
                if(result){ // We made an episode!
                    $scope.tag_and_close(result);
                }else{
				    $modalInstance.close(result);
                }
			});
        };

        // Let's have a nice way to kill the modal.
        $scope.cancel = function() {
	        $modalInstance.close('cancel');
        };
    }
);
<commit_msg>Set OPAT referral to date of referral. Refactor OPAT referral saving to use promise.all() API<commit_after>//
// This is our "Enter OPAT" flow controller
//
controllers.controller(
    'OPATReferralCtrl',
    function($scope, $modalInstance, $modal, $rootScope, $q,
             schema, options,
             Episode){

        $scope.model = {
            hospital_number : null
        }
        $scope.patient = null;

        //
        // When we've created an episode with this flow, tag it to the correct
        // teams and then kill the modal.
        //
        $scope.tag_and_close = function(episode){
            if(!episode.newItem){
                episode = new Episode(episode, schema);
            };
            if(!episode.tagging[0].makeCopy){
                episode.tagging[0] = episode.newItem('tagging');
            }
            var teams = episode.tagging[0].makeCopy();
            var location = episode.location[0].makeCopy();
            teams.opat = true;
            teams.opat_referrals = true;
            location.category = 'OPAT';
            location.opat_referral = moment();

            //
            // Pre fill some tests:
            //
            var mrsa = episode.newItem('microbiology_test');
            var vte = episode.newItem('microbiology_test');

            $q.all([
                episode.tagging[0].save(teams),
                episode.location[0].save(location),
                mrsa.save({test: 'MRSA PCR'}),
                vte.save({test: 'VTE Assessment'})
            ]).then(function(){
                episode.active = true;
                $modalInstance.close(episode);
            });

        };

        //
        // We have an initial hospital number - we can now figure out whether to
        // Add or pull over.
        //
        $scope.find_by_hospital_number = function(){
            Episode.findByHospitalNumber(
                $scope.model.hospital_number,
                {
                    newPatient: $scope.new_patient,
                    newForPatient: $scope.new_for_patient,
                    error: function(){
			            // This shouldn't happen, but we should probably handle it better
			            alert('ERROR: More than one patient found with hospital number');
                        $modalInstance.close(null)
                    }
                }
            );
        };

        //
        // Create a new patient
        //
        $scope.new_patient = function(result){
			// There is no patient with this hospital number
			// Show user the form for creating a new episode,
            // with the hospital number pre-populated
			modal = $modal.open({
				templateUrl: '/templates/modals/opat/add_episode.html/',
				controller: 'AddEpisodeCtrl',
				resolve: {
					schema: function() { return schema; },
					options: function() { return options; },
					demographics: function() {
						return { hospital_number: $scope.hospital_number }
					}
				}
			}).result.then(function(result) {
				// The user has created the episode, or cancelled
                if(result){ // We made an episode!
                    $scope.tag_and_close(result);
                }else{
				    $modalInstance.close(result);
                }
			});
        };

        //
        // Create a new episode for an existing patient
        //
        $scope.new_for_patient = function(patient){
            if(patient.active_episode_id && _.keys(patient.episodes).length > 0){
                // Offer to import the data from this episode.
				for (var eix in patient.episodes) {
					patient.episodes[eix] = new Episode(patient.episodes[eix], schema);
				};
				modal = $modal.open({
					templateUrl: '/templates/modals/copy_to_category.html/',
					controller: 'CopyToCategoryCtrl',
					resolve: {
                        category: function() { return 'OPAT' },
						patient: function() { return patient; },
					}
				}).result.then(
                    function(result) {
                        if(!_.isString(result)){
                            $scope.tag_and_close(result);
                            return
                        };
					    if (result == 'open-new') {
						    // User has chosen to open a new episode
                            $scope.add_for_patient(patient);
					    } else {
						    // User has chosen to reopen an episode, or cancelled
						    $modalInstance.close(result);
					    };
				    },
                    function(result){ $modalInstance.close(result); });
            }else{
                $scope.add_for_patient(patient);
            };
        };

        //
        // Add a new episode for an existing patient. Pre-fill the relevant demographics
        //
        $scope.add_for_patient = function(patient){
            var demographics = patient.demographics[0];
            if(demographics.date_of_birth){
                var dob = moment(demographics.date_of_birth, 'YYYY-MM-DD')
                    .format('DD/MM/YYYY');
				demographics.date_of_birth = dob;
            }
			modal = $modal.open({
				templateUrl: '/templates/modals/opat/add_episode.html/',
				controller: 'AddEpisodeCtrl',
				resolve: {
					schema: function() { return schema; },
					options: function() { return options; },
					demographics: function() { return demographics; }
				}
			}).result.then(function(result) {
				// The user has created the episode, or cancelled
                if(result){ // We made an episode!
                    $scope.tag_and_close(result);
                }else{
				    $modalInstance.close(result);
                }
			});
        };

        // Let's have a nice way to kill the modal.
        $scope.cancel = function() {
	        $modalInstance.close('cancel');
        };
    }
);
<|endoftext|>


<commit_before>var __ = require('underscore'),
    Backbone = require('backbone'),
    $ = require('jquery'),
    loadTemplate = require('../utils/loadTemplate'),
    messageModal = require('../utils/messageModal.js'),
    setTheme = require('../utils/setTheme.js'),
    chosen = require('../utils/chosen.jquery.min.js'),
    transactionsCl = require('../collections/transactionsCl'),
    baseVw = require('./baseVw'),
    orderShortVw = require('./orderShortVw'),
    getBTPrice = require('../utils/getBitcoinPrice'),
    transactionModalVw = require('./transactionModalVw'),
    countriesMd = require('../models/countriesMd');

module.exports = baseVw.extend({

  className: "transactionsView",

  events: {
    'click .js-purchasesTab': 'tabHandler',
    'click .js-salesTab': 'tabHandler',
    'click .js-casesTab': 'tabHandler',
    'change .js-transactionFilter': 'transactionFilter',
    'keyup .search': 'searchKeyup',
    'click .js-transactionsSearchClear': 'searchClear'
  },

  initialize: function(options){
    "use strict";
    /* expected options:
       userModel
       userProfile
       state (from router)
       orderID (from router)
       socketView (from router)
     */
    var self = this,
        profile = options.userProfile.get('profile'),
        wrapper = "

";

    this.options = options;
    this.state = options.state || "purchases";
    this.orderID = options.orderID;
    this.userModel = options.userModel;
    this.userProfile = options.userProfile;
    this.model = new Backbone.Model();
    this.model.set("user", options.userModel.toJSON());
    this.model.set("page", profile);
    this.socketView = options.socketView;
    setTheme(profile.primary_color, profile.secondary_color, profile.background_color, profile.text_color);
    this.serverUrl = options.userModel.get('serverUrl');
    this.cCode = options.userModel.get('currency_code');
    this.listenTo(window.obEventBus, "openOrderModal", function(orderID){
      self.openOrderModal(orderID);
    });
    this.searchTransactions;
    this.filterBy; //used for filtering the collections

    this.countries = new countriesMd();
    this.countriesArray = this.countries.get('countries');

    this.purchasesWrapper = $(wrapper);
    this.salesWrapper = $(wrapper);
    this.casesWrapper = $(wrapper);

    this.listenTo(window.obEventBus, "socketMessageReceived", this.handleSocketMessage);
    this.listenTo(window.obEventBus, "orderModalClosed", function(){
      this.orderID = "";
      this.getData();
    });

    $('.js-loadingModal').removeClass("hide");
    getBTPrice(this.cCode, function(btAve){
      $('.js-loadingModal').addClass("hide");
      self.btAve = btAve;
      self.purchasesCol = new transactionsCl(null, {btAve: btAve, cCode: self.cCode});
      self.purchasesCol.url = self.serverUrl + "get_purchases";

      self.salesCol = new transactionsCl(null, {btAve: btAve, cCode: self.cCode});
      self.salesCol.url = self.serverUrl + "get_sales";

      self.casesCol = new transactionsCl(null, {btAve: btAve, cCode: self.cCode});
      self.casesCol.url = self.serverUrl + "get_cases";

      self.render();
    });
  },

  getData: function(){
    "use strict";
    var self = this;

    this.purchasesCol.fetch({
      success: function(models){
        //self.renderPurchases();
        self.renderTab("purchases", self.purchasesCol, self.purchasesWrapper);
        models.length && self.setSearchList('transactionsPurchases');
        self.salesCol.fetch({
          success: function(models){
            if(self.model.get('page').vendor) {
              self.renderTab("sales", self.salesCol, self.salesWrapper);
              models.length && self.setSearchList('transactionsSales');
            }
            self.casesCol.fetch({
              success: function(models) {
                //self.renderCases();
                self.renderTab("cases", self.casesCol, self.casesWrapper);
                models.length && self.setSearchList('transactionsCases');
              },
              error: function(jqXHR, status, errorThrown){
                messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
                console.log(jqXHR);
                console.log(status);
                console.log(errorThrown);
              }
            }).always(function(){
              //if page was opened with an orderID, open that tab and open the order modal
              //find the order
              if(self.orderID){
                var tType = '';
                var orderModelP = self.purchasesCol.findWhere({ order_id: self.orderID});
                var orderModelS = self.salesCol.findWhere({ order_id: self.orderID});
                var orderModelC = self.casesCol.findWhere({ order_id: self.orderID});
                var orderModel = orderModelP || orderModelS || orderModelC;

                if(orderModelP){
                  tType = "purchases";
                  self.setState('purchases', self.orderID)
                } else if(orderModelS){
                  tType = "sales";
                  self.setState('sales', self.orderID)
                } else if(orderModelC){
                  tType = "cases";
                  self.setState('cases', self.orderID)
                }

                if(orderModel){
                  self.openOrderModal({
                    'orderID': self.orderID,
                    'status': orderModel.get('status'),
                    'transactionType': tType
                  });
                }
              }
            });
          },
          error: function(jqXHR, status, errorThrown){
            messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
            console.log(jqXHR);
            console.log(status);
            console.log(errorThrown);
          }
        });
      },
      error: function(jqXHR, status, errorThrown){
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  handleSocketMessage: function(response) {
    var data = JSON.parse(response.data);
    if(data.notification && data.notification.order_id){
      this.getData();
    }
  },

  setSearchList: function(targetID){
    "use strict";
    this.searchTransactions = new window.List(targetID, {valueNames: ['js-searchOrderID', 'js-searchStatus', 'js-searchTitle'], page: 1000});
  },

  render: function(){
    "use strict";
    var self = this;
    $('#content').html(self.$el);
    loadTemplate('./js/templates/transactions.html', function(loadedTemplate) {
      self.$el.html(loadedTemplate(self.model.toJSON()));
      self.setState(self.state);
      self.getData();
    });
  },

  setTab: function(activeTab, showContent){
    "use strict";
    this.$el.find('.js-tab').removeClass('active');
    activeTab.addClass('active');
    this.$el.find('.js-tabTarg').addClass('hide');
    showContent.removeClass('hide');
  },

  setState: function(state, orderID){
    var addID = orderID ? "/" + orderID : "";
    this.setTab(this.$el.find('.js-' + state + 'Tab'), this.$el.find('.js-' + state));
    //add action to history
    Backbone.history.navigate("#transactions/" + state + addID);
  },

  tabHandler: function(e){
    "use strict";
    var tab = $(e.target).closest('.js-tab'),
        tabID = tab.data("tab"),
        showContent = this.$el.find('.js-'+tabID);

    this.filterBy = '';
    this.setTab(tab, showContent);
    this.setState(tabID);
  },

  searchKeyup: function(e){
    "use strict";
    this.$('.js-transactionsSearchClear').removeClass('hide');
  },

  searchClear: function(){
    "use strict";
    this.$('.search').val("");
    this.$('.js-transactionsSearchClear').addClass('hide');
    this.renderPurchases();
  },

  transactionFilter: function(e){
    "use strict";
    var tab = $(e.target),
        tabTarget = tab.data("tab");

    this.filterBy = tab.val();
    this.$('.js-'+tabTarget+' .search').val("");
    switch(tabTarget){
      case "purchases":
        this.renderTab("purchases", this.purchasesCol, this.purchasesWrapper);
        break;
      case "sales":
        this.renderTab("sales", this.salesCol, this.salesWrapper);
        break;
      case "cases":
        this.renderTab("cases", this.casesCol, this.casesWrapper);
        break;
    }
  },

  renderTab: function(tabName, tabCollection, tabWrapper, filterBy){
    "use strict";
    var self = this;
    filterBy = filterBy || this.filterBy;
    tabWrapper.html('');
    if(!filterBy || filterBy == "all" || filterBy == "dateNewest"){
      tabCollection.comparator = function(model) {
        return -model.get("timestamp");
      };
      tabCollection.sort();
    }
    if(filterBy == "dateOldest"){
      tabCollection.comparator = function(model) {
        return model.get("timestamp");
      };
      tabCollection.sort();
    }
    tabCollection.each(function(model, i){
      if(!filterBy || filterBy == "all" || filterBy == "dateNewest" || filterBy == "dateOldest"){
        self.addTransaction(model, tabWrapper, tabName);
      } else if(filterBy && filterBy != "dateNewest" && filterBy != "dateOldest" && model.get('status') == filterBy) {
        self.addTransaction(model, tabWrapper, tabName);
      }
    });

    this.$el.find('.js-'+tabName+'Count').html(tabCollection.length);
    this.$el.find('.js-'+tabName).append(tabWrapper);
  },

  addTransaction: function(model, tabWrapper, type){
    model.set('imageUrl', this.serverUrl +"get_image?hash="+ model.get('thumbnail_hash'));
    model.set('transactionType', type);
    var orderShort = new orderShortVw({
      model: model
    });
    this.registerChild(orderShort);
    tabWrapper.append(orderShort.render().el);
  },

  openOrderModal: function(options){
    "use strict";
    $('.js-loadingModal').removeClass("hide");
    if(options.status == "open"){
      options.status = 4;
    }
    var orderModalView = new transactionModalVw({
      orderID: options.orderID,
      status: options.status,
      serverUrl: this.serverUrl,
      parentEl: $('#modalHolder'),
      countriesArray: this.countriesArray,
      cCode: this.userModel.get('currency_code'),
      btAve: this.btAve,
      state: this.state,
      tabState: options.tabState,
      bitcoinValidationRegex: btcRegex,
      transactionType: options.transactionType,
      userModel: this.userModel,
      userProfile: this.userProfile,
      socketView: this.socketView
    });
    this.registerChild(orderModalView);
  }
});<commit_msg>remove redundant code<commit_after>var __ = require('underscore'),
    Backbone = require('backbone'),
    $ = require('jquery'),
    loadTemplate = require('../utils/loadTemplate'),
    messageModal = require('../utils/messageModal.js'),
    setTheme = require('../utils/setTheme.js'),
    chosen = require('../utils/chosen.jquery.min.js'),
    transactionsCl = require('../collections/transactionsCl'),
    baseVw = require('./baseVw'),
    orderShortVw = require('./orderShortVw'),
    getBTPrice = require('../utils/getBitcoinPrice'),
    transactionModalVw = require('./transactionModalVw'),
    countriesMd = require('../models/countriesMd');

module.exports = baseVw.extend({

  className: "transactionsView",

  events: {
    'click .js-purchasesTab': 'tabHandler',
    'click .js-salesTab': 'tabHandler',
    'click .js-casesTab': 'tabHandler',
    'change .js-transactionFilter': 'transactionFilter',
    'keyup .search': 'searchKeyup',
    'click .js-transactionsSearchClear': 'searchClear'
  },

  initialize: function(options){
    "use strict";
    /* expected options:
       userModel
       userProfile
       state (from router)
       orderID (from router)
       socketView (from router)
     */
    var self = this,
        profile = options.userProfile.get('profile'),
        wrapper = "

";

    this.options = options;
    this.state = options.state || "purchases";
    this.orderID = options.orderID;
    this.userModel = options.userModel;
    this.userProfile = options.userProfile;
    this.model = new Backbone.Model();
    this.model.set("user", options.userModel.toJSON());
    this.model.set("page", profile);
    this.socketView = options.socketView;
    setTheme(profile.primary_color, profile.secondary_color, profile.background_color, profile.text_color);
    this.serverUrl = options.userModel.get('serverUrl');
    this.cCode = options.userModel.get('currency_code');
    this.listenTo(window.obEventBus, "openOrderModal", function(orderID){
      self.openOrderModal(orderID);
    });
    this.searchTransactions;
    this.filterBy; //used for filtering the collections

    this.countries = new countriesMd();
    this.countriesArray = this.countries.get('countries');

    this.purchasesWrapper = $(wrapper);
    this.salesWrapper = $(wrapper);
    this.casesWrapper = $(wrapper);

    this.listenTo(window.obEventBus, "socketMessageReceived", this.handleSocketMessage);
    this.listenTo(window.obEventBus, "orderModalClosed", function(){
      this.orderID = "";
      this.getData();
    });

    $('.js-loadingModal').removeClass("hide");
    getBTPrice(this.cCode, function(btAve){
      $('.js-loadingModal').addClass("hide");
      self.btAve = btAve;
      self.purchasesCol = new transactionsCl(null, {btAve: btAve, cCode: self.cCode});
      self.purchasesCol.url = self.serverUrl + "get_purchases";

      self.salesCol = new transactionsCl(null, {btAve: btAve, cCode: self.cCode});
      self.salesCol.url = self.serverUrl + "get_sales";

      self.casesCol = new transactionsCl(null, {btAve: btAve, cCode: self.cCode});
      self.casesCol.url = self.serverUrl + "get_cases";

      self.render();
    });
  },

  getData: function(){
    "use strict";
    var self = this;

    this.purchasesCol.fetch({
      success: function(models){
        //self.renderPurchases();
        self.renderTab("purchases", self.purchasesCol, self.purchasesWrapper);
        models.length && self.setSearchList('transactionsPurchases');
        self.salesCol.fetch({
          success: function(models){
            if(self.model.get('page').vendor) {
              self.renderTab("sales", self.salesCol, self.salesWrapper);
              models.length && self.setSearchList('transactionsSales');
            }
            self.casesCol.fetch({
              success: function(models) {
                //self.renderCases();
                self.renderTab("cases", self.casesCol, self.casesWrapper);
                models.length && self.setSearchList('transactionsCases');
              },
              error: function(jqXHR, status, errorThrown){
                messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
                console.log(jqXHR);
                console.log(status);
                console.log(errorThrown);
              }
            }).always(function(){
              //if page was opened with an orderID, open that tab and open the order modal
              //find the order
              if(self.orderID){
                var tType = '';
                var orderModelP = self.purchasesCol.findWhere({ order_id: self.orderID});
                var orderModelS = self.salesCol.findWhere({ order_id: self.orderID});
                var orderModelC = self.casesCol.findWhere({ order_id: self.orderID});
                var orderModel = orderModelP || orderModelS || orderModelC;

                if(orderModelP){
                  tType = "purchases";
                  self.setState('purchases', self.orderID)
                } else if(orderModelS){
                  tType = "sales";
                  self.setState('sales', self.orderID)
                } else if(orderModelC){
                  tType = "cases";
                  self.setState('cases', self.orderID)
                }

                if(orderModel){
                  self.openOrderModal({
                    'orderID': self.orderID,
                    'status': orderModel.get('status'),
                    'transactionType': tType
                  });
                }
              }
            });
          },
          error: function(jqXHR, status, errorThrown){
            messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
            console.log(jqXHR);
            console.log(status);
            console.log(errorThrown);
          }
        });
      },
      error: function(jqXHR, status, errorThrown){
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  handleSocketMessage: function(response) {
    var data = JSON.parse(response.data);
    if(data.notification && data.notification.order_id){
      this.getData();
    }
  },

  setSearchList: function(targetID){
    "use strict";
    this.searchTransactions = new window.List(targetID, {valueNames: ['js-searchOrderID', 'js-searchStatus', 'js-searchTitle'], page: 1000});
  },

  render: function(){
    "use strict";
    var self = this;
    $('#content').html(self.$el);
    loadTemplate('./js/templates/transactions.html', function(loadedTemplate) {
      self.$el.html(loadedTemplate(self.model.toJSON()));
      self.setState(self.state);
      self.getData();
    });
  },

  setTab: function(activeTab, showContent){
    "use strict";
    this.$el.find('.js-tab').removeClass('active');
    activeTab.addClass('active');
    this.$el.find('.js-tabTarg').addClass('hide');
    showContent.removeClass('hide');
  },

  setState: function(state, orderID){
    var addID = orderID ? "/" + orderID : "";
    this.setTab(this.$el.find('.js-' + state + 'Tab'), this.$el.find('.js-' + state));
    //add action to history
    Backbone.history.navigate("#transactions/" + state + addID);
  },

  tabHandler: function(e){
    "use strict";
    var tab = $(e.target).closest('.js-tab'),
        tabID = tab.data("tab"),
        showContent = this.$el.find('.js-'+tabID);

    this.filterBy = '';
    this.setTab(tab, showContent);
    this.setState(tabID);
  },

  searchKeyup: function(e){
    "use strict";
    this.$('.js-transactionsSearchClear').removeClass('hide');
  },

  searchClear: function(){
    "use strict";
    this.$('.search').val("");
    this.$('.js-transactionsSearchClear').addClass('hide');
    this.renderPurchases();
  },

  transactionFilter: function(e){
    "use strict";
    var tab = $(e.target),
        tabTarget = tab.data("tab");

    this.filterBy = tab.val();
    this.$('.js-'+tabTarget+' .search').val("");
    switch(tabTarget){
      case "purchases":
        this.renderTab("purchases", this.purchasesCol, this.purchasesWrapper);
        break;
      case "sales":
        this.renderTab("sales", this.salesCol, this.salesWrapper);
        break;
      case "cases":
        this.renderTab("cases", this.casesCol, this.casesWrapper);
        break;
    }
  },

  renderTab: function(tabName, tabCollection, tabWrapper, filterBy){
    "use strict";
    var self = this;
    filterBy = filterBy || this.filterBy;
    tabWrapper.html('');
    if(!filterBy || filterBy == "all" || filterBy == "dateNewest"){
      tabCollection.comparator = function(model) {
        return -model.get("timestamp");
      };
      tabCollection.sort();
    }
    if(filterBy == "dateOldest"){
      tabCollection.comparator = function(model) {
        return model.get("timestamp");
      };
      tabCollection.sort();
    }
    tabCollection.each(function(model, i){
      if(!filterBy || filterBy == "all" || filterBy == "dateNewest" || filterBy == "dateOldest"){
        self.addTransaction(model, tabWrapper, tabName);
      } else if(filterBy && filterBy != "dateNewest" && filterBy != "dateOldest" && model.get('status') == filterBy) {
        self.addTransaction(model, tabWrapper, tabName);
      }
    });

    this.$el.find('.js-'+tabName+'Count').html(tabCollection.length);
    this.$el.find('.js-'+tabName).append(tabWrapper);
  },

  addTransaction: function(model, tabWrapper, type){
    model.set('imageUrl', this.serverUrl +"get_image?hash="+ model.get('thumbnail_hash'));
    model.set('transactionType', type);
    var orderShort = new orderShortVw({
      model: model
    });
    this.registerChild(orderShort);
    tabWrapper.append(orderShort.render().el);
  },

  openOrderModal: function(options){
    "use strict";
    $('.js-loadingModal').removeClass("hide");
    if(options.status == "open"){
      options.status = 4;
    }
    var orderModalView = new transactionModalVw({
      orderID: options.orderID,
      status: options.status,
      serverUrl: this.serverUrl,
      parentEl: $('#modalHolder'),
      countriesArray: this.countriesArray,
      cCode: this.userModel.get('currency_code'),
      btAve: this.btAve,
      state: this.state,
      tabState: options.tabState,
      transactionType: options.transactionType,
      userModel: this.userModel,
      userProfile: this.userProfile,
      socketView: this.socketView
    });
    this.registerChild(orderModalView);
  }
});<|endoftext|>


<commit_before>import treeFavicon from '../img/tree_open.png';
import closedTreeFavicon from '../img/tree_closed.png';

// TODO: This file is a handy catch-all, but we could likely move some of these
// to a specific helper or into the classes that use them.

export const thPlatformMap = {
  linux32: 'Linux',
  'linux32-devedition': 'Linux DevEdition',
  'linux32-nightly': 'Linux Nightly',
  'linux32-shippable': 'Linux shippable',
  linux64: 'Linux x64',
  'linux64-asan': 'Linux x64 asan',
  'linux64-asan-qr': 'Linux x64 QuantumRender asan',
  'linux64-asan-reporter': 'Linux x64 asan reporter',
  'linux64-add-on-devel': 'Linux x64 addon',
  'linux64-devedition': 'Linux x64 DevEdition',
  'linux64-pgo-qr': 'Linux x64 QuantumRender pgo',
  'linux64-shippable-qr': 'Linux x64 QuantumRender Shippable',
  'linux64-qr': 'Linux x64 QuantumRender',
  'linux64-nightly': 'Linux x64 Nightly',
  'linux64-shippable': 'Linux x64 shippable',
  'linux64-stylo-sequential': 'Linux x64 Stylo-Seq',
  'linux64-ccov': 'Linux x64 CCov',
  'linux64-noopt': 'Linux x64 NoOpt',
  'linux64-aarch64': 'Linux AArch64',
  'osx-10-10': 'OS X 10.10',
  'osx-1010-64': 'OS X 10.10',
  'osx-1014-64': 'OS X 10.14',
  'osx-cross': 'OS X Cross Compiled',
  'osx-10-10-shippable': 'OS X 10.10 shippable',
  'osx-1010-64-shippable': 'OS X 10.10 shippable',
  'osx-1014-64-shippable': 'OS X 10.14 shippable',
  'osx-shippable': 'OS X Cross Compiled shippable',
  'osx-cross-noopt': 'OS X Cross Compiled NoOpt',
  'osx-cross-add-on-devel': 'OS X Cross Compiled addon',
  'osx-cross-ccov': 'OS X Cross Compiled CCov',
  'osx-cross-devedition': 'OS X Cross Compiled DevEdition',
  'macosx64-qr': 'OS X 10.10 QuantumRender',
  'macosx64-shippable-qr': 'OS X 10.10 QuantumRender Shippable',
  'macosx64-devedition': 'OS X 10.10 DevEdition',
  'macosx64-nightly': 'OS X 10.10 Nightly',
  'macosx64-ccov': 'OS X 10.10 Cross Compiled CCov',
  'macosx1010-64': 'OS X 10.10',
  'macosx1010-64-qr': 'OS X 10.10 QuantumRender',
  'macosx1010-64-shippable-qr': 'OS X 10.10 QuantumRender Shippable',
  'macosx1010-64-shippable': 'OS X 10.10 Shippable',
  'macosx1010-64-devedition': 'OS X 10.10 DevEdition',
  'macosx1010-64-nightly': 'OS X 10.10 Nightly',
  'macosx1010-64-ccov': 'OS X 10.10 Cross Compiled CCov',
  'macosx1014-64': 'OS X 10.14',
  'macosx1014-64-qr': 'OS X 10.14 QuantumRender',
  'macosx1014-64-shippable': 'OS X 10.14 Shippable',
  'macosx1014-64-shippable-qr': 'OS X 10.14 QuantumRender Shippable',
  'macosx1014-64-devedition': 'OS X 10.14 DevEdition',
  'macosx1014-64-nightly': 'OS X 10.14 Nightly',
  'macosx1014-64-ccov': 'OS X 10.14 Cross Compiled CCov',
  'windows7-32': 'Windows 7',
  'windows7-32-devedition': 'Windows 7 DevEdition',
  'windows7-32-nightly': 'Windows 7 VM Nightly',
  'windows7-32-shippable': 'Windows 7 Shippable',
  'windows7-32-mingwclang': 'Windows 7 MinGW',
  'windows10-64': 'Windows 10 x64',
  'windows10-64-ccov': 'Windows 10 x64 CCov',
  'windows10-64-devedition': 'Windows 10 x64 DevEdition',
  'windows10-64-nightly': 'Windows 10 x64 Nightly',
  'windows10-64-pgo-qr': 'Windows 10 x64 QuantumRender pgo',
  'windows10-64-shippable': 'Windows 10 x64 Shippable',
  'windows10-64-shippable-qr': 'Windows 10 x64 QuantumRender Shippable',
  'windows10-64-qr': 'Windows 10 x64 QuantumRender',
  'windows10-64-ref-hw-2017': 'Windows 10 x64 2017 Ref HW',
  'windows10-64-mingwclang': 'Windows 10 x64 MinGW',
  'windows10-aarch64': 'Windows 10 AArch64',
  'windows2012-32': 'Windows 2012',
  'windows2012-32-shippable': 'Windows 2012 shippable',
  'windows2012-32-add-on-devel': 'Windows 2012 addon',
  'windows2012-32-noopt': 'Windows 2012 NoOpt',
  'windows2012-32-devedition': 'Windows 2012 DevEdition',
  'windows2012-64': 'Windows 2012 x64',
  'windows2012-64-shippable': 'Windows 2012 x64 shippable',
  'windows2012-aarch64': 'Windows 2012 AArch64',
  'windows2012-aarch64-shippable': 'Windows 2012 AArch64 Shippable',
  'windows2012-aarch64-devedition': 'Windows 2012 AArch64 DevEdition',
  'win64-asan-reporter': 'Windows 2012 x64 asan reporter',
  'windows2012-64-add-on-devel': 'Windows 2012 x64 addon',
  'windows2012-64-noopt': 'Windows 2012 x64 NoOpt',
  'windows2012-64-devedition': 'Windows 2012 x64 DevEdition',
  'windows-mingw32': 'Windows MinGW',

  'android-4-0-armv7-api16': 'Android 4.0 API16+',
  'android-4-0-armv7-api16-beta': 'Android 4.0 API16+ Beta',
  'android-4-0-armv7-api16-release': 'Android 4.0 API16+ Release',
  'android-4-0-armv7-api16-ccov': 'Android 4.0 API16+ CCov',
  'android-4-0-geckoview-fat-aar':
    'Android 4.0 API16+ GeckoView multi-arch fat AAR',
  'android-4-2-x86': 'Android 4.2 x86',
  'android-4-2-x86-beta': 'Android 4.2 x86 Beta',
  'android-4-2-x86-release': 'Android 4.2 x86 Release',
  'android-em-4-2-x86': 'Android 4.2 x86',
  'android-em-4-2-x86-beta': 'Android 4.2 x86 Beta',
  'android-em-4-2-x86-release': 'Android 4.2 x86 Release',
  'android-em-4-3-armv7-api16': 'Android 4.3 API16+',
  'android-em-4-3-armv7-api16-beta': 'Android 4.3 API16+ Beta',
  'android-em-4-3-armv7-api16-ccov': 'Android 4.3 API16+ CCov',
  'android-em-4-3-armv7-api16-release': 'Android 4.3 API16+ Release',
  'android-5-0-aarch64': 'Android 5.0 AArch64',
  'android-5-0-aarch64-beta': 'Android 5.0 AArch64 Beta',
  'android-5-0-aarch64-release': 'Android 5.0 AArch64 Release',
  'android-5-0-x86_64': 'Android 5.0 x86-64',
  'android-5-0-x86_64-beta': 'Android 5.0 x86-64 Beta',
  'android-5-0-x86_64-release': 'Android 5.0 x86-64 Release',
  'android-em-7-0-x86': 'Android 7.0 x86',
  'android-em-7-0-x86-beta': 'Android 7.0 x86 Beta',
  'android-em-7-0-x86-release': 'Android 7.0 x86 Release',
  'android-em-7-0-x86_64': 'Android 7.0 x86-64',
  'android-em-7-0-x86_64-beta': 'Android 7.0 x86-64 Beta',
  'android-em-7-0-x86_64-release': 'Android 7.0 x86-64 Release',
  'android-hw-g5-7-0-arm7-api-16': 'Android 7.0 MotoG5',
  'android-hw-p2-8-0-arm7-api-16': 'Android 8.0 Pixel2',
  'android-hw-p2-8-0-arm7-api-16-qr': 'Android 8.0 Pixel2 QuantumRender',
  'android-hw-p2-8-0-arm7-api-16-nightly': 'Android 8.0 Pixel2 Nightly',
  'android-hw-p2-8-0-android-aarch64': 'Android 8.0 Pixel2 AArch64',
  'android-hw-p2-8-0-android-aarch64-nightly':
    'Android 8.0 Pixel2 AArch64 Nightly',
  Android: 'Android',

  'gecko-decision': 'Gecko Decision Task',
  'firefox-release': 'Firefox Release Tasks',
  'devedition-release': 'Devedition Release Tasks',
  'fennec-beta': 'Fennec Beta Tasks',
  'fennec-release': 'Fennec Release Tasks',
  'thunderbird-release': 'Thunderbird Release Tasks',
  diff: 'Diffoscope',
  lint: 'Linting',
  fetch: 'Fetch',
  'taskcluster-images': 'Docker Images',
  packages: 'Packages',
  toolchains: 'Toolchains',
  other: 'Other',
};

// Platforms where the `opt` should be dropped from
export const thSimplePlatforms = [
  'gecko-decision',
  'firefox-release',
  'devedition-release',
  'fennec-beta',
  'fennec-release',
  'thunderbird-release',
  'lint',
  'taskcluster-images',
  'packages',
  'toolchains',
  'diff',
];

export const thFailureResults = ['testfailed', 'busted', 'exception'];

export const thAllResultStatuses = [
  'testfailed',
  'busted',
  'exception',
  'success',
  'retry',
  'usercancel',
  'superseded',
  'running',
  'pending',
  'runnable',
];

export const thOptionOrder = {
  opt: 1,
  pgo: 2,
  asan: 3,
  tsan: 4,
  debug: 5,
  cc: 6,
  addon: 7,
  all: 8,
};

export const thFavicons = {
  closed: closedTreeFavicon,
  open: treeFavicon,
  'approval required': treeFavicon,
  unavailable: treeFavicon,
};

export const thDefaultRepo = 'autoland';

export const thJobNavSelectors = {
  ALL_JOBS: {
    name: 'jobs',
    selector: '.job-btn, .selected-job, .selected-count',
  },
  UNCLASSIFIED_FAILURES: {
    name: 'unclassified failures',
    selector:
      '.selected-job, .job-btn.btn-red, .job-btn.btn-orange, .job-btn.btn-purple',
  },
};

export const thPerformanceBranches = ['autoland', 'mozilla-inbound'];

/**
 * The set of custom Treeherder events.
 */
export const thEvents = {
  // fired with a selected job on 't'
  selectNextTab: 'select-next-tab-EVT',
  // fired with a selected job on 'r'
  jobRetrigger: 'job-retrigger-EVT',
  // fired when job classifications change (created/deleted)
  classificationChanged: 'classification-changed-EVT',
  saveClassification: 'save-classification-EVT',
  deleteClassification: 'delete-classification-EVT',
  openLogviewer: 'open-logviewer-EVT',
  applyNewJobs: 'apply-new-jobs-EVT',
  filtersUpdated: 'filters-updated-EVT',
  clearPinboard: 'clear-pinboard-EVT',
};

export const thBugSuggestionLimit = 20;

export const thMaxPushFetchSize = 100;

export const errorMessageClass = 'text-danger py-4 d-block text-center';

export const genericErrorMessage = 'Something went wrong';
<commit_msg>Bug 1602863 - pretty treeherder labels for linux1804 jobs (#5802)<commit_after>import treeFavicon from '../img/tree_open.png';
import closedTreeFavicon from '../img/tree_closed.png';

// TODO: This file is a handy catch-all, but we could likely move some of these
// to a specific helper or into the classes that use them.

export const thPlatformMap = {
  linux32: 'Linux',
  'linux32-devedition': 'Linux DevEdition',
  'linux32-nightly': 'Linux Nightly',
  'linux32-shippable': 'Linux shippable',
  'linux1804-32-shippable': 'Linux 18.04 shippable',
  linux64: 'Linux x64',
  'linux64-asan': 'Linux x64 asan',
  'linux64-asan-qr': 'Linux x64 QuantumRender asan',
  'linux64-asan-reporter': 'Linux x64 asan reporter',
  'linux64-add-on-devel': 'Linux x64 addon',
  'linux64-devedition': 'Linux x64 DevEdition',
  'linux64-pgo-qr': 'Linux x64 QuantumRender pgo',
  'linux64-shippable-qr': 'Linux x64 QuantumRender Shippable',
  'linux64-qr': 'Linux x64 QuantumRender',
  'linux64-nightly': 'Linux x64 Nightly',
  'linux64-shippable': 'Linux x64 shippable',
  'linux64-stylo-sequential': 'Linux x64 Stylo-Seq',
  'linux64-ccov': 'Linux x64 CCov',
  'linux64-noopt': 'Linux x64 NoOpt',
  'linux64-aarch64': 'Linux AArch64',
  'linux1804-64': 'Linux 18.04 x64',
  'linux1804-64-asan': 'Linux 18.04 x64 asan',
  'linux1804-64-asan-qr': 'Linux 18.04 x64 QuantumRender asan',
  'linux1804-64-devedition': 'Linux 18.04 x64 DevEdition',
  'linux1804-64-shippable-qr': 'Linux 18.04 x64 QuantumRender Shippable',
  'linux1804-64-qr': 'Linux 18.04 x64 QuantumRender',
  'linux1804-64-shippable': 'Linux 18.04 x64 shippable',
  'linux1804-64-stylo-sequential': 'Linux 18.04 x64 Stylo-Seq',
  'linux1804-64-ccov': 'Linux 18.04 x64 CCov',
  'osx-10-10': 'OS X 10.10',
  'osx-1010-64': 'OS X 10.10',
  'osx-1014-64': 'OS X 10.14',
  'osx-cross': 'OS X Cross Compiled',
  'osx-10-10-shippable': 'OS X 10.10 shippable',
  'osx-1010-64-shippable': 'OS X 10.10 shippable',
  'osx-1014-64-shippable': 'OS X 10.14 shippable',
  'osx-shippable': 'OS X Cross Compiled shippable',
  'osx-cross-noopt': 'OS X Cross Compiled NoOpt',
  'osx-cross-add-on-devel': 'OS X Cross Compiled addon',
  'osx-cross-ccov': 'OS X Cross Compiled CCov',
  'osx-cross-devedition': 'OS X Cross Compiled DevEdition',
  'macosx64-qr': 'OS X 10.10 QuantumRender',
  'macosx64-shippable-qr': 'OS X 10.10 QuantumRender Shippable',
  'macosx64-devedition': 'OS X 10.10 DevEdition',
  'macosx64-nightly': 'OS X 10.10 Nightly',
  'macosx64-ccov': 'OS X 10.10 Cross Compiled CCov',
  'macosx1010-64': 'OS X 10.10',
  'macosx1010-64-qr': 'OS X 10.10 QuantumRender',
  'macosx1010-64-shippable-qr': 'OS X 10.10 QuantumRender Shippable',
  'macosx1010-64-shippable': 'OS X 10.10 Shippable',
  'macosx1010-64-devedition': 'OS X 10.10 DevEdition',
  'macosx1010-64-nightly': 'OS X 10.10 Nightly',
  'macosx1010-64-ccov': 'OS X 10.10 Cross Compiled CCov',
  'macosx1014-64': 'OS X 10.14',
  'macosx1014-64-qr': 'OS X 10.14 QuantumRender',
  'macosx1014-64-shippable': 'OS X 10.14 Shippable',
  'macosx1014-64-shippable-qr': 'OS X 10.14 QuantumRender Shippable',
  'macosx1014-64-devedition': 'OS X 10.14 DevEdition',
  'macosx1014-64-nightly': 'OS X 10.14 Nightly',
  'macosx1014-64-ccov': 'OS X 10.14 Cross Compiled CCov',
  'windows7-32': 'Windows 7',
  'windows7-32-devedition': 'Windows 7 DevEdition',
  'windows7-32-nightly': 'Windows 7 VM Nightly',
  'windows7-32-shippable': 'Windows 7 Shippable',
  'windows7-32-mingwclang': 'Windows 7 MinGW',
  'windows10-64': 'Windows 10 x64',
  'windows10-64-ccov': 'Windows 10 x64 CCov',
  'windows10-64-devedition': 'Windows 10 x64 DevEdition',
  'windows10-64-nightly': 'Windows 10 x64 Nightly',
  'windows10-64-pgo-qr': 'Windows 10 x64 QuantumRender pgo',
  'windows10-64-shippable': 'Windows 10 x64 Shippable',
  'windows10-64-shippable-qr': 'Windows 10 x64 QuantumRender Shippable',
  'windows10-64-qr': 'Windows 10 x64 QuantumRender',
  'windows10-64-ref-hw-2017': 'Windows 10 x64 2017 Ref HW',
  'windows10-64-mingwclang': 'Windows 10 x64 MinGW',
  'windows10-aarch64': 'Windows 10 AArch64',
  'windows2012-32': 'Windows 2012',
  'windows2012-32-shippable': 'Windows 2012 shippable',
  'windows2012-32-add-on-devel': 'Windows 2012 addon',
  'windows2012-32-noopt': 'Windows 2012 NoOpt',
  'windows2012-32-devedition': 'Windows 2012 DevEdition',
  'windows2012-64': 'Windows 2012 x64',
  'windows2012-64-shippable': 'Windows 2012 x64 shippable',
  'windows2012-aarch64': 'Windows 2012 AArch64',
  'windows2012-aarch64-shippable': 'Windows 2012 AArch64 Shippable',
  'windows2012-aarch64-devedition': 'Windows 2012 AArch64 DevEdition',
  'win64-asan-reporter': 'Windows 2012 x64 asan reporter',
  'windows2012-64-add-on-devel': 'Windows 2012 x64 addon',
  'windows2012-64-noopt': 'Windows 2012 x64 NoOpt',
  'windows2012-64-devedition': 'Windows 2012 x64 DevEdition',
  'windows-mingw32': 'Windows MinGW',

  'android-4-0-armv7-api16': 'Android 4.0 API16+',
  'android-4-0-armv7-api16-beta': 'Android 4.0 API16+ Beta',
  'android-4-0-armv7-api16-release': 'Android 4.0 API16+ Release',
  'android-4-0-armv7-api16-ccov': 'Android 4.0 API16+ CCov',
  'android-4-0-geckoview-fat-aar':
    'Android 4.0 API16+ GeckoView multi-arch fat AAR',
  'android-4-2-x86': 'Android 4.2 x86',
  'android-4-2-x86-beta': 'Android 4.2 x86 Beta',
  'android-4-2-x86-release': 'Android 4.2 x86 Release',
  'android-em-4-2-x86': 'Android 4.2 x86',
  'android-em-4-2-x86-beta': 'Android 4.2 x86 Beta',
  'android-em-4-2-x86-release': 'Android 4.2 x86 Release',
  'android-em-4-3-armv7-api16': 'Android 4.3 API16+',
  'android-em-4-3-armv7-api16-beta': 'Android 4.3 API16+ Beta',
  'android-em-4-3-armv7-api16-ccov': 'Android 4.3 API16+ CCov',
  'android-em-4-3-armv7-api16-release': 'Android 4.3 API16+ Release',
  'android-5-0-aarch64': 'Android 5.0 AArch64',
  'android-5-0-aarch64-beta': 'Android 5.0 AArch64 Beta',
  'android-5-0-aarch64-release': 'Android 5.0 AArch64 Release',
  'android-5-0-x86_64': 'Android 5.0 x86-64',
  'android-5-0-x86_64-beta': 'Android 5.0 x86-64 Beta',
  'android-5-0-x86_64-release': 'Android 5.0 x86-64 Release',
  'android-em-7-0-x86': 'Android 7.0 x86',
  'android-em-7-0-x86-beta': 'Android 7.0 x86 Beta',
  'android-em-7-0-x86-release': 'Android 7.0 x86 Release',
  'android-em-7-0-x86_64': 'Android 7.0 x86-64',
  'android-em-7-0-x86_64-beta': 'Android 7.0 x86-64 Beta',
  'android-em-7-0-x86_64-release': 'Android 7.0 x86-64 Release',
  'android-hw-g5-7-0-arm7-api-16': 'Android 7.0 MotoG5',
  'android-hw-p2-8-0-arm7-api-16': 'Android 8.0 Pixel2',
  'android-hw-p2-8-0-arm7-api-16-qr': 'Android 8.0 Pixel2 QuantumRender',
  'android-hw-p2-8-0-arm7-api-16-nightly': 'Android 8.0 Pixel2 Nightly',
  'android-hw-p2-8-0-android-aarch64': 'Android 8.0 Pixel2 AArch64',
  'android-hw-p2-8-0-android-aarch64-nightly':
    'Android 8.0 Pixel2 AArch64 Nightly',
  Android: 'Android',

  'gecko-decision': 'Gecko Decision Task',
  'firefox-release': 'Firefox Release Tasks',
  'devedition-release': 'Devedition Release Tasks',
  'fennec-beta': 'Fennec Beta Tasks',
  'fennec-release': 'Fennec Release Tasks',
  'thunderbird-release': 'Thunderbird Release Tasks',
  diff: 'Diffoscope',
  lint: 'Linting',
  fetch: 'Fetch',
  'taskcluster-images': 'Docker Images',
  packages: 'Packages',
  toolchains: 'Toolchains',
  other: 'Other',
};

// Platforms where the `opt` should be dropped from
export const thSimplePlatforms = [
  'gecko-decision',
  'firefox-release',
  'devedition-release',
  'fennec-beta',
  'fennec-release',
  'thunderbird-release',
  'lint',
  'taskcluster-images',
  'packages',
  'toolchains',
  'diff',
];

export const thFailureResults = ['testfailed', 'busted', 'exception'];

export const thAllResultStatuses = [
  'testfailed',
  'busted',
  'exception',
  'success',
  'retry',
  'usercancel',
  'superseded',
  'running',
  'pending',
  'runnable',
];

export const thOptionOrder = {
  opt: 1,
  pgo: 2,
  asan: 3,
  tsan: 4,
  debug: 5,
  cc: 6,
  addon: 7,
  all: 8,
};

export const thFavicons = {
  closed: closedTreeFavicon,
  open: treeFavicon,
  'approval required': treeFavicon,
  unavailable: treeFavicon,
};

export const thDefaultRepo = 'autoland';

export const thJobNavSelectors = {
  ALL_JOBS: {
    name: 'jobs',
    selector: '.job-btn, .selected-job, .selected-count',
  },
  UNCLASSIFIED_FAILURES: {
    name: 'unclassified failures',
    selector:
      '.selected-job, .job-btn.btn-red, .job-btn.btn-orange, .job-btn.btn-purple',
  },
};

export const thPerformanceBranches = ['autoland', 'mozilla-inbound'];

/**
 * The set of custom Treeherder events.
 */
export const thEvents = {
  // fired with a selected job on 't'
  selectNextTab: 'select-next-tab-EVT',
  // fired with a selected job on 'r'
  jobRetrigger: 'job-retrigger-EVT',
  // fired when job classifications change (created/deleted)
  classificationChanged: 'classification-changed-EVT',
  saveClassification: 'save-classification-EVT',
  deleteClassification: 'delete-classification-EVT',
  openLogviewer: 'open-logviewer-EVT',
  applyNewJobs: 'apply-new-jobs-EVT',
  filtersUpdated: 'filters-updated-EVT',
  clearPinboard: 'clear-pinboard-EVT',
};

export const thBugSuggestionLimit = 20;

export const thMaxPushFetchSize = 100;

export const errorMessageClass = 'text-danger py-4 d-block text-center';

export const genericErrorMessage = 'Something went wrong';
<|endoftext|>


<commit_before>// Load in dependencies
var fs = require('fs');
var expect = require('chai').expect;
var sinon = require('sinon');
var shell = require('shelljs');
var fixtureUtils = require('./utils/fixtures');
var Foundry = require('../bin/foundry');

// Guarantee safeguards against exec are in place (see WARNING.md)
var childUtils = require('./utils/child-process');

// Define our test
describe('A release', function () {
  describe.only('in a node module (npm)', function () {
    fixtureUtils.fixtureDir('npm');
    // TODO: Make this a util itself
    // foundryUtils.release('0.1.0');
    before(function release (done) {
      // Introduce custom stubbing
      var program = new Foundry();
      var that = this;
      childUtils.shellExec._allow();
      childUtils.childExec._allow();
      program.once('postRelease#before', function banAndStub () {
        childUtils.shellExec._ban();
        childUtils.childExec._ban();
        that.execStub = sinon.stub(shell, 'exec', function () {
          return {code: 0};
        });
      });

      // Set up our callback
      program.once('postRelease#after', done);

      // Run through the release
      program.parse(['node', '/usr/bin/foundry', 'release', '0.1.0']);
    });
    after(function unstub () {
      this.execStub.restore();
    });

    it('updates the package.json', function () {
      var pkgJson = fs.readFileSync(fixtureUtils.dir + '/npm/package.json');
      expect(JSON.parse(pkgJson)).to.have.property('version', '0.1.0');
    });
    it('publishes to npm', function () {
      expect(this.execStub.args[1]).to.deep.equal(['npm publish']);
    });

    // TODO: Test private
    it.skip('does not attempt to publish private packages', function () {
    });
  });

  describe.skip('in a bower module', function () {
  });
  describe.skip('in a component module', function () {
  });
  describe.skip('in a PyPI package', function () {
  });
});
<commit_msg>Removed dev .only<commit_after>// Load in dependencies
var fs = require('fs');
var expect = require('chai').expect;
var sinon = require('sinon');
var shell = require('shelljs');
var fixtureUtils = require('./utils/fixtures');
var Foundry = require('../bin/foundry');

// Guarantee safeguards against exec are in place (see WARNING.md)
var childUtils = require('./utils/child-process');

// Define our test
describe('A release', function () {
  describe('in a node module (npm)', function () {
    fixtureUtils.fixtureDir('npm');
    // TODO: Make this a util itself
    // foundryUtils.release('0.1.0');
    before(function release (done) {
      // Introduce custom stubbing
      var program = new Foundry();
      var that = this;
      childUtils.shellExec._allow();
      childUtils.childExec._allow();
      program.once('postRelease#before', function banAndStub () {
        childUtils.shellExec._ban();
        childUtils.childExec._ban();
        that.execStub = sinon.stub(shell, 'exec', function () {
          return {code: 0};
        });
      });

      // Set up our callback
      program.once('postRelease#after', done);

      // Run through the release
      program.parse(['node', '/usr/bin/foundry', 'release', '0.1.0']);
    });
    after(function unstub () {
      this.execStub.restore();
    });

    it('updates the package.json', function () {
      var pkgJson = fs.readFileSync(fixtureUtils.dir + '/npm/package.json');
      expect(JSON.parse(pkgJson)).to.have.property('version', '0.1.0');
    });
    it('publishes to npm', function () {
      expect(this.execStub.args[1]).to.deep.equal(['npm publish']);
    });

    // TODO: Test private
    it.skip('does not attempt to publish private packages', function () {
    });
  });

  describe.skip('in a bower module', function () {
  });
  describe.skip('in a component module', function () {
  });
  describe.skip('in a PyPI package', function () {
  });
});
<|endoftext|>


<commit_before>import treeFavicon from '../img/tree_open.png';
import closedTreeFavicon from '../img/tree_closed.png';

// TODO: This file is a handy catch-all, but we could likely move some of these
// to a specific helper or into the classes that use them.

export const thPlatformMap = {
  linux32: 'Linux',
  'linux32-devedition': 'Linux DevEdition',
  'linux32-qr': 'Linux QuantumRender',
  'linux32-nightly': 'Linux Nightly',
  'linux32-stylo': 'Linux Stylo',
  'linux32-stylo-disabled': 'Linux Stylo Disabled',
  linux64: 'Linux x64',
  'linux64-asan': 'Linux x64 asan',
  'linux64-add-on-devel': 'Linux x64 addon',
  'linux64-devedition': 'Linux x64 DevEdition',
  'linux64-qr': 'Linux x64 QuantumRender',
  'linux64-nightly': 'Linux x64 Nightly',
  'linux64-stylo': 'Linux x64 Stylo',
  'linux64-stylo-disabled': 'Linux x64 Stylo Disabled',
  'linux64-stylo-sequential': 'Linux x64 Stylo-Seq',
  'linux64-ccov': 'Linux x64 CCov',
  'linux64-jsdcov': 'Linux x64 JSDCov',
  'linux64-noopt': 'Linux x64 NoOpt',
  'linux64-dmd': 'Linux x64 DMD',
  'osx-10-6': 'OS X 10.6',
  'osx-10-7': 'OS X 10.7',
  'osx-10-7-add-on-devel': 'OS X 10.7 addon',
  'osx-10-7-devedition': 'OS X 10.7 DevEdition',
  'osx-10-8': 'OS X 10.8',
  'osx-10-9': 'OS X 10.9',
  'osx-10-10': 'OS X 10.10',
  'osx-10-10-devedition': 'OS X 10.10 DevEdition',
  'osx-10-10-dmd': 'OS X 10.10 DMD',
  'osx-10-11': 'OS X 10.11',
  'osx-10-7-noopt': 'OS X 10.7 NoOpt',
  'osx-cross': 'OS X Cross Compiled',
  'osx-cross-noopt': 'OS X Cross Compiled NoOpt',
  'osx-cross-add-on-devel': 'OS X Cross Compiled addon',
  'osx-cross-ccov': 'OS X Cross Compiled CCov',
  'osx-cross-devedition': 'OS X Cross Compiled DevEdition',
  'macosx64-qr': 'OS X 10.10 QuantumRender',
  'macosx64-stylo': 'OS X 10.10 Stylo',
  'macosx64-stylo-disabled': 'OS X 10.10 Stylo Disabled',
  'macosx64-devedition': 'OS X 10.10 DevEdition',
  'macosx64-nightly': 'OS X 10.10 Nightly',
  windowsxp: 'Windows XP',
  'windowsxp-devedition': 'Windows XP DevEdition',
  'windows7-32': 'Windows 7',
  'windows7-32-vm': 'Windows 7 VM',
  'windows7-32-devedition': 'Windows 7 DevEdition',
  'windows7-32-stylo-disabled': 'Windows 7 Stylo Disabled',
  'windows7-32-vm-devedition': 'Windows 7 VM DevEdition',
  'windows7-32-nightly': 'Windows 7 VM Nightly',
  'windows7-32-stylo': 'Windows 7 VM Stylo',
  'windows7-64': 'Windows 7 x64',
  'windows8-32': 'Windows 8',
  'windows8-64': 'Windows 8 x64',
  'windows8-64-devedition': 'Windows 8 x64 DevEdition',
  'windows10-32': 'Windows 10',
  'windows10-64': 'Windows 10 x64',
  'windows10-64-ccov': 'Windows 10 x64 CCov',
  'windows10-64-vm': 'Windows 10 x64 VM',
  'windows10-64-devedition': 'Windows 10 x64 DevEdition',
  'windows10-64-nightly': 'Windows 10 x64 Nightly',
  'windows10-64-stylo': 'Windows 10 x64 Stylo',
  'windows10-64-stylo-disabled': 'Windows 10 x64 Stylo Disabled',
  'windows10-64-qr': 'Windows 10 x64 QuantumRender',
  'windows2012-32': 'Windows 2012',
  'windows2012-32-add-on-devel': 'Windows 2012 addon',
  'windows2012-32-noopt': 'Windows 2012 NoOpt',
  'windows2012-32-devedition': 'Windows 2012 DevEdition',
  'windows2012-32-dmd': 'Windows 2012 DMD',
  'windows2012-64': 'Windows 2012 x64',
  'windows2012-aarch64': 'Windows 2012 AArch64',
  'windows2012-64-add-on-devel': 'Windows 2012 x64 addon',
  'windows2012-64-noopt': 'Windows 2012 x64 NoOpt',
  'windows2012-64-devedition': 'Windows 2012 x64 DevEdition',
  'windows2012-64-dmd': 'Windows 2012 x64 DMD',
  'windows-mingw32': 'Windows MinGW',

  'android-2-2-armv6': 'Android 2.2 Armv6',
  'android-2-2': 'Android 2.2',
  'android-2-3-armv6': 'Android 2.3 Armv6',
  'android-2-3': 'Android 2.3',
  'android-2-3-armv7-api9': 'Android 2.3 API9',
  'android-4-0': 'Android 4.0',
  'android-4-0-armv7-api10': 'Android 4.0 API10+',
  'android-4-0-armv7-api11': 'Android 4.0 API11+',
  'android-4-0-armv7-api15': 'Android 4.0 API15+',
  'android-4-0-armv7-api15-old-id': 'Android 4.0 API15+ OldId',
  'android-4-0-armv7-api16': 'Android 4.0 API16+',
  'android-em-4-0-armv7-api16': 'Android 4.0 API16+',
  'android-4-0-armv7-api16-old-id': 'Android 4.0 API16+ OldId',
  'android-4-0-armv7-api16-ccov': 'Android 4.0 API16+ CCov',
  'android-4-2-x86': 'Android 4.2 x86',
  'android-em-4-2-x86': 'Android 4.2 x86',
  'android-4-2-x86-old-id': 'Android 4.2 x86 OldId',
  'android-4-2': 'Android 4.2',
  'android-4-2-armv7-api11': 'Android 4.2 API11+',
  'android-4-2-armv7-api15': 'Android 4.2 API15+',
  'android-4-2-armv7-api16': 'Android 4.2 API16+',
  'android-em-4-2-armv7-api16': 'Android 4.2 API16+',
  'android-4-3': 'Android 4.3',
  'android-4-3-armv7-api11': 'Android 4.3 API11+',
  'android-4-3-armv7-api15': 'Android 4.3 API15+',
  'android-4-3-armv7-api16': 'Android 4.3 API16+',
  'android-em-4-3-armv7-api16': 'Android 4.3 API16+',
  'android-em-4-3-armv7-api16-ccov': 'Android 4.3 API16+ CCov',
  'android-4-4': 'Android 4.4',
  'android-4-4-armv7-api11': 'Android 4.4 API11+',
  'android-4-4-armv7-api15': 'Android 4.4 API15+',
  'android-4-4-armv7-api16': 'Android 4.4 API16+',
  'android-5-0-aarch64': 'Android 5.0 AArch64',
  'android-5-0-armv7-api11': 'Android 5.0 API11+',
  'android-5-0-armv7-api15': 'Android 5.0 API15+',
  'android-5-0-armv8-api15': 'Android 5.0 API15+',
  'android-5-0-armv8-api16': 'Android 5.0 API16+',
  'android-5-0-x86_64': 'Android 5.0 x86-64',
  'android-5-1-armv7-api15': 'Android 5.1 API15+',
  'android-6-0-armv8-api15': 'Android 6.0 API15+',
  'android-6-0-armv8-api16': 'Android 6.0 API16+',
  'android-em-7-0-x86': 'Android 7.0 x86',
  'android-7-1-armv8-api15': 'Android 7.1 API15+',
  'android-7-1-armv8-api16': 'Android 7.1 API16+',
  'b2gdroid-4-0-armv7-api11': 'B2GDroid 4.0 API11+',
  'b2gdroid-4-0-armv7-api15': 'B2GDroid 4.0 API15+',
  'android-4-0-armv7-api11-partner1': 'Android API11+ partner1',
  'android-4-0-armv7-api15-partner1': 'Android API15+ partner1',
  'android-api-15-gradle': 'Android API15+ Gradle',
  'android-api-16-gradle': 'Android API16+ Gradle',
  'android-hw-g5-7-0-arm7-api-16': 'Android 7.0 MotoG5',
  'android-hw-p2-8-0-arm7-api-16': 'Android 8.0 Pixel2',
  'android-hw-p2-8-0-android-aarch64': 'Android 8.0 Pixel2 AArch64',
  Android: 'Android',

  'b2g-linux32': 'B2G Desktop Linux',
  'b2g-linux64': 'B2G Desktop Linux x64',
  'b2g-osx': 'B2G Desktop OS X',
  'b2g-win32': 'B2G Desktop Windows',
  'b2g-emu-ics': 'B2G ICS Emulator',
  'b2g-emu-jb': 'B2G JB Emulator',
  'b2g-emu-kk': 'B2G KK Emulator',
  'b2g-emu-x86-kk': 'B2G KK Emulator x86',
  'b2g-emu-l': 'B2G L Emulator',
  'b2g-device-image': 'B2G Device Image',
  'mulet-linux32': 'Mulet Linux',
  'mulet-linux64': 'Mulet Linux x64',
  'mulet-osx': 'Mulet OS X',
  'mulet-win32': 'Mulet Windows',

  'graphene-linux64': 'Graphene Linux x64',
  'graphene-osx': 'Graphene OS X',
  'graphene-win64': 'Graphene Windows x64',
  'horizon-linux64': 'Horizon Linux x64',
  'horizon-osx': 'Horizon OS X',
  'horizon-win64': 'Horizon Windows x64',

  'gecko-decision': 'Gecko Decision Task',
  'firefox-release': 'Firefox Release Tasks',
  'devedition-release': 'Devedition Release Tasks',
  'fennec-release': 'Fennec Release Tasks',
  'thunderbird-release': 'Thunderbird Release Tasks',
  lint: 'Linting',
  'release-mozilla-release-': 'Balrog Publishing',
  'taskcluster-images': 'Docker Images',
  packages: 'Packages',
  toolchains: 'Toolchains',
  diff: 'Diffoscope',
  other: 'Other',
};

// Platforms where the `opt` should be dropped from
export const thSimplePlatforms = [
  'gecko-decision',
  'firefox-release',
  'devedition-release',
  'fennec-release',
  'thunderbird-release',
  'lint',
  'release-mozilla-release-',
  'taskcluster-images',
  'packages',
  'toolchains',
  'diff',
];

export const thFailureResults = ['testfailed', 'busted', 'exception'];

export const thAllResultStatuses = [
  'testfailed',
  'busted',
  'exception',
  'success',
  'retry',
  'usercancel',
  'superseded',
  'running',
  'pending',
  'runnable',
];

export const thOptionOrder = {
  opt: 0,
  pgo: 1,
  asan: 2,
  tsan: 3,
  debug: 4,
  cc: 5,
  addon: 6,
  all: 7,
};

export const thFavicons = {
  closed: closedTreeFavicon,
  open: treeFavicon,
  'approval required': treeFavicon,
  unavailable: treeFavicon,
};

export const thDefaultRepo = 'mozilla-inbound';

export const thDateFormat = 'EEE MMM d, HH:mm:ss';

export const thJobNavSelectors = {
  ALL_JOBS: {
    name: 'jobs',
    selector: '.job-btn, .selected-job, .selected-count',
  },
  UNCLASSIFIED_FAILURES: {
    name: 'unclassified failures',
    selector:
      '.selected-job, .job-btn.btn-red, .job-btn.btn-orange, .job-btn.btn-purple, .job-btn.autoclassified',
  },
};

export const thPerformanceBranches = ['autoland', 'mozilla-inbound'];

/**
 * The set of custom Treeherder events.
 */
export const thEvents = {
  // fired with a selected job on 't'
  selectNextTab: 'select-next-tab-EVT',
  // fired with a selected job on 'r'
  jobRetrigger: 'job-retrigger-EVT',
  // fired when job classifications change (created/deleted)
  classificationChanged: 'classification-changed-EVT',
  saveClassification: 'save-classification-EVT',
  deleteClassification: 'delete-classification-EVT',
  openLogviewer: 'open-logviewer-EVT',
  autoclassifyIgnore: 'ac-ignore-EVT',
  applyNewJobs: 'apply-new-jobs-EVT',
};

export const phTimeRanges = [
  { value: 86400, text: 'Last day' },
  { value: 86400 * 2, text: 'Last 2 days' },
  { value: 604800, text: 'Last 7 days' },
  { value: 1209600, text: 'Last 14 days' },
  { value: 2592000, text: 'Last 30 days' },
  { value: 5184000, text: 'Last 60 days' },
  { value: 7776000, text: 'Last 90 days' },
  { value: 31536000, text: 'Last year' },
];

export const phDefaultTimeRangeValue = 1209600;

export const phTimeRangeValues = {
  'mozilla-beta': 7776000,
};

export const phDefaultFramework = 'talos';

export const phFrameworksWithRelatedBranches = [
  1, // talos
  10, // raptor
  11, // js-bench
  12, // devtools
];

export const phAlertSummaryStatusMap = {
  UNTRIAGED: { id: 0, text: 'untriaged' },
  DOWNSTREAM: { id: 1, text: 'downstream' },
  REASSIGNED: { id: 2, text: 'reassigned' },
  INVALID: { id: 3, text: 'invalid' },
  IMPROVEMENT: { id: 4, text: 'improvement' },
  INVESTIGATING: { id: 5, text: 'investigating' },
  WONTFIX: { id: 6, text: 'wontfix' },
  FIXED: { id: 7, text: 'fixed' },
  BACKEDOUT: { id: 8, text: 'backedout' },
  CONFIRMING: { id: 9, text: 'confirming' },
};

export const phAlertStatusMap = {
  UNTRIAGED: { id: 0, text: 'untriaged' },
  DOWNSTREAM: { id: 1, text: 'downstream' },
  REASSIGNED: { id: 2, text: 'reassigned' },
  INVALID: { id: 3, text: 'invalid' },
  ACKNOWLEDGED: { id: 4, text: 'acknowledged' },
  CONFIRMING: { id: 5, text: 'confirming' },
};

export const compareDefaultTimeRange = 86400 * 2;

export const thBugSuggestionLimit = 20;

export const thMaxPushFetchSize = 100;

export const errorMessageClass = 'text-danger py-4 d-block text-center';

export const genericErrorMessage = 'Something went wrong';
<commit_msg>Bug 1524537 - Update platform mappings (#4545)<commit_after>import treeFavicon from '../img/tree_open.png';
import closedTreeFavicon from '../img/tree_closed.png';

// TODO: This file is a handy catch-all, but we could likely move some of these
// to a specific helper or into the classes that use them.

export const thPlatformMap = {
  linux32: 'Linux',
  'linux32-devedition': 'Linux DevEdition',
  'linux32-nightly': 'Linux Nightly',
  linux64: 'Linux x64',
  'linux64-asan': 'Linux x64 asan',
  'linux64-asan-reporter': 'Linux x64 asan reporter',
  'linux64-add-on-devel': 'Linux x64 addon',
  'linux64-devedition': 'Linux x64 DevEdition',
  'linux64-qr': 'Linux x64 QuantumRender',
  'linux64-nightly': 'Linux x64 Nightly',
  'linux64-stylo-sequential': 'Linux x64 Stylo-Seq',
  'linux64-ccov': 'Linux x64 CCov',
  'linux64-noopt': 'Linux x64 NoOpt',
  'osx-10-10': 'OS X 10.10',
  'osx-cross': 'OS X Cross Compiled',
  'osx-cross-noopt': 'OS X Cross Compiled NoOpt',
  'osx-cross-add-on-devel': 'OS X Cross Compiled addon',
  'osx-cross-ccov': 'OS X Cross Compiled CCov',
  'osx-cross-devedition': 'OS X Cross Compiled DevEdition',
  'macosx64-qr': 'OS X 10.10 QuantumRender',
  'macosx64-devedition': 'OS X 10.10 DevEdition',
  'macosx64-nightly': 'OS X 10.10 Nightly',
  'macosx64-ccov': 'OS X 10.10 Cross Compiled CCov',
  'windows7-32': 'Windows 7',
  'windows7-32-devedition': 'Windows 7 DevEdition',
  'windows7-32-nightly': 'Windows 7 VM Nightly',
  'windows10-64': 'Windows 10 x64',
  'windows10-64-ccov': 'Windows 10 x64 CCov',
  'windows10-64-devedition': 'Windows 10 x64 DevEdition',
  'windows10-64-nightly': 'Windows 10 x64 Nightly',
  'windows10-64-qr': 'Windows 10 x64 QuantumRender',
  'windows10-64-ux': 'Windows 10 x64 HW UX',
  'windows2012-32': 'Windows 2012',
  'windows2012-32-add-on-devel': 'Windows 2012 addon',
  'windows2012-32-noopt': 'Windows 2012 NoOpt',
  'windows2012-32-devedition': 'Windows 2012 DevEdition',
  'windows2012-64': 'Windows 2012 x64',
  'windows2012-aarch64': 'Windows 2012 AArch64',
  'win64-asan-reporter': 'Windows 2012 x64 asan reporter',
  'windows2012-64-add-on-devel': 'Windows 2012 x64 addon',
  'windows2012-64-noopt': 'Windows 2012 x64 NoOpt',
  'windows2012-64-devedition': 'Windows 2012 x64 DevEdition',
  'windows-mingw32': 'Windows MinGW',

  'android-4-0-armv7-api16': 'Android 4.0 API16+',
  'android-4-0-armv7-api16-ccov': 'Android 4.0 API16+ CCov',
  'android-4-2-x86': 'Android 4.2 x86',
  'android-em-4-2-x86': 'Android 4.2 x86',
  'android-em-4-3-armv7-api16': 'Android 4.3 API16+',
  'android-em-4-3-armv7-api16-ccov': 'Android 4.3 API16+ CCov',
  'android-5-0-aarch64': 'Android 5.0 AArch64',
  'android-5-0-x86_64': 'Android 5.0 x86-64',
  'android-em-7-0-x86': 'Android 7.0 x86',
  'android-hw-g5-7-0-arm7-api-16': 'Android 7.0 MotoG5',
  'android-hw-p2-8-0-arm7-api-16': 'Android 8.0 Pixel2',
  'android-hw-p2-8-0-arm7-api-16-nightly': 'Android 8.0 Pixel2 Nightly',
  'android-hw-p2-8-0-android-aarch64': 'Android 8.0 Pixel2 AArch64',
  'android-hw-p2-8-0-android-aarch64-nightly':
    'Android 8.0 Pixel2 AArch64 Nightly',
  Android: 'Android',

  'gecko-decision': 'Gecko Decision Task',
  'firefox-release': 'Firefox Release Tasks',
  'devedition-release': 'Devedition Release Tasks',
  'fennec-release': 'Fennec Release Tasks',
  'thunderbird-release': 'Thunderbird Release Tasks',
  lint: 'Linting',
  'taskcluster-images': 'Docker Images',
  packages: 'Packages',
  toolchains: 'Toolchains',
  other: 'Other',
};

// Platforms where the `opt` should be dropped from
export const thSimplePlatforms = [
  'gecko-decision',
  'firefox-release',
  'devedition-release',
  'fennec-release',
  'thunderbird-release',
  'lint',
  'taskcluster-images',
  'packages',
  'toolchains',
  'diff',
];

export const thFailureResults = ['testfailed', 'busted', 'exception'];

export const thAllResultStatuses = [
  'testfailed',
  'busted',
  'exception',
  'success',
  'retry',
  'usercancel',
  'superseded',
  'running',
  'pending',
  'runnable',
];

export const thOptionOrder = {
  opt: 0,
  pgo: 1,
  asan: 2,
  tsan: 3,
  debug: 4,
  cc: 5,
  addon: 6,
  all: 7,
};

export const thFavicons = {
  closed: closedTreeFavicon,
  open: treeFavicon,
  'approval required': treeFavicon,
  unavailable: treeFavicon,
};

export const thDefaultRepo = 'mozilla-inbound';

export const thDateFormat = 'EEE MMM d, HH:mm:ss';

export const thJobNavSelectors = {
  ALL_JOBS: {
    name: 'jobs',
    selector: '.job-btn, .selected-job, .selected-count',
  },
  UNCLASSIFIED_FAILURES: {
    name: 'unclassified failures',
    selector:
      '.selected-job, .job-btn.btn-red, .job-btn.btn-orange, .job-btn.btn-purple, .job-btn.autoclassified',
  },
};

export const thPerformanceBranches = ['autoland', 'mozilla-inbound'];

/**
 * The set of custom Treeherder events.
 */
export const thEvents = {
  // fired with a selected job on 't'
  selectNextTab: 'select-next-tab-EVT',
  // fired with a selected job on 'r'
  jobRetrigger: 'job-retrigger-EVT',
  // fired when job classifications change (created/deleted)
  classificationChanged: 'classification-changed-EVT',
  saveClassification: 'save-classification-EVT',
  deleteClassification: 'delete-classification-EVT',
  openLogviewer: 'open-logviewer-EVT',
  autoclassifyIgnore: 'ac-ignore-EVT',
  applyNewJobs: 'apply-new-jobs-EVT',
};

export const phTimeRanges = [
  { value: 86400, text: 'Last day' },
  { value: 86400 * 2, text: 'Last 2 days' },
  { value: 604800, text: 'Last 7 days' },
  { value: 1209600, text: 'Last 14 days' },
  { value: 2592000, text: 'Last 30 days' },
  { value: 5184000, text: 'Last 60 days' },
  { value: 7776000, text: 'Last 90 days' },
  { value: 31536000, text: 'Last year' },
];

export const phDefaultTimeRangeValue = 1209600;

export const phTimeRangeValues = {
  'mozilla-beta': 7776000,
};

export const phDefaultFramework = 'talos';

export const phFrameworksWithRelatedBranches = [
  1, // talos
  10, // raptor
  11, // js-bench
  12, // devtools
];

export const phAlertSummaryStatusMap = {
  UNTRIAGED: { id: 0, text: 'untriaged' },
  DOWNSTREAM: { id: 1, text: 'downstream' },
  REASSIGNED: { id: 2, text: 'reassigned' },
  INVALID: { id: 3, text: 'invalid' },
  IMPROVEMENT: { id: 4, text: 'improvement' },
  INVESTIGATING: { id: 5, text: 'investigating' },
  WONTFIX: { id: 6, text: 'wontfix' },
  FIXED: { id: 7, text: 'fixed' },
  BACKEDOUT: { id: 8, text: 'backedout' },
  CONFIRMING: { id: 9, text: 'confirming' },
};

export const phAlertStatusMap = {
  UNTRIAGED: { id: 0, text: 'untriaged' },
  DOWNSTREAM: { id: 1, text: 'downstream' },
  REASSIGNED: { id: 2, text: 'reassigned' },
  INVALID: { id: 3, text: 'invalid' },
  ACKNOWLEDGED: { id: 4, text: 'acknowledged' },
  CONFIRMING: { id: 5, text: 'confirming' },
};

export const compareDefaultTimeRange = 86400 * 2;

export const thBugSuggestionLimit = 20;

export const thMaxPushFetchSize = 100;

export const errorMessageClass = 'text-danger py-4 d-block text-center';

export const genericErrorMessage = 'Something went wrong';
<|endoftext|>


<commit_before>import React from 'react';
import Select from 'react-select';
import omit from 'lodash/object/omit';
import cx from 'classnames';
import { props, t } from '../utils';
import { warn } from '../utils/log';

const themes = {
  semantic: 'semantic-theme'
};

const PropTypes = {
  children: t.maybe(t.ReactNode),
  theme: t.maybe(t.enums.of(['semantic'])),
  valueLink: t.maybe(t.struct({
    value: t.maybe(t.String),
    requestChange: t.Function
  }))
};
@props(PropTypes, { strict: false })
export default class Dropdown extends React.Component {

  componentDidMount() {
    this.logWarnings();
  }

  getChildren = () => [].concat(this.props.children || []);

  renderOption = (option) => this.getChildren()[option.value];

  renderValue = (option) => this.getChildren()[option.value];

  getGeneralProps = () => omit(this.props, Object.keys(PropTypes));

  logWarnings = () => {
    if (this.props.children) {
      warn('You\'re passing children. Not expected behaviour');
    }
  };

  getValueLinkProps = () => {
    if (this.props.valueLink) {
      return {
        value: this.props.valueLink.value,
        onChange: this.props.valueLink.requestChange
      };
    }
  };

  getClassName = () => cx(this.props.className, themes[this.props.theme]);

  render() {
    // The order is important: props may override previous ones
    return (
      <Select
        {...this.getGeneralProps()}
        {...this.getValueLinkProps()}
        {...this.getClassName()}
      />
    );
  }

}
<commit_msg>fix comment and code cleaning<commit_after>import React from 'react';
import Select from 'react-select';
import omit from 'lodash/object/omit';
import cx from 'classnames';
import { props, t } from '../utils';
import { warn } from '../utils/log';

const themes = {
  semantic: 'semantic-theme'
};

const PropTypes = {
  children: t.maybe(t.ReactNode),
  theme: t.maybe(t.enums.of(['semantic'])),
  valueLink: t.maybe(t.struct({
    value: t.maybe(t.String),
    requestChange: t.Function
  }))
};
@props(PropTypes, { strict: false })
export default class Dropdown extends React.Component {

  componentDidMount() {
    this.logWarnings();
  }

  getGeneralProps = () => omit(this.props, Object.keys(PropTypes));

  logWarnings = () => {
    if (this.props.children) {
      warn('You\'re passing children. Not expected behaviour');
    }
  };

  getValueLinkProps = () => {
    if (this.props.valueLink) {
      return {
        value: this.props.valueLink.value,
        onChange: this.props.valueLink.requestChange
      };
    }
  };

  getClassName = () => cx(this.props.className, themes[this.props.theme]);

  render() {
    // The order is important: props may override previous ones
    return (
      <Select
        {...this.getGeneralProps()}
        {...this.getValueLinkProps()}
        {...this.getClassName()}
      />
    );
  }

}
<|endoftext|>


<commit_before>import Immutable from 'seamless-immutable';
import * as R from 'ramda';
import { FORM_ERROR } from 'final-form';
import FileSaver from 'file-saver';
import * as Constants from '../constants/ActionTypes';
import { api } from '../Network';

export const submitForm = (formId) => {
  document
    .getElementById(formId)
    .dispatchEvent(new Event('submit', { cancelable: true }));
};

export const fileSave = (uri, filename) => () => api()
  .get(uri, { responseType: 'blob' })
  .then((response) => {
    FileSaver.saveAs(response.data, filename);
  });

export const fileDownload = (uri) => () => api().get(uri, { responseType: 'blob' });

export const simpleCall = (uri) => api().get(uri);

export const getReferential = (schema, uri, noloading) => (dispatch) => {
  if (noloading !== true) {
    dispatch({ type: Constants.DATA_FETCH_SUBMITTED });
  }
  return api(schema)
    .get(uri)
    .then((response) => {
      dispatch({ type: Constants.DATA_FETCH_SUCCESS, payload: response.data });
      return response.data;
    })
    .catch((error) => {
      dispatch({ type: Constants.DATA_FETCH_ERROR, payload: error });
      throw error;
    });
};

export const putReferential = (schema, uri, data) => (dispatch) => {
  dispatch({ type: Constants.DATA_FETCH_SUBMITTED });
  return api(schema)
    .put(uri, data)
    .then((response) => {
      dispatch({ type: Constants.DATA_FETCH_SUCCESS, payload: response.data });
      dispatch({ type: Constants.DATA_UPDATE_SUCCESS, payload: response.data });
      return response.data;
    })
    .catch((error) => {
      dispatch({ type: Constants.DATA_FETCH_ERROR, payload: error });
      throw error;
    });
};

export const postReferential = (schema, uri, data) => (dispatch) => {
  dispatch({ type: Constants.DATA_FETCH_SUBMITTED });
  return api(schema)
    .post(uri, data)
    .then((response) => {
      dispatch({ type: Constants.DATA_FETCH_SUCCESS, payload: response.data });
      return response.data;
    })
    .catch((error) => {
      dispatch({ type: Constants.DATA_FETCH_ERROR, payload: error });
      throw error;
    });
};

export const delReferential = (uri, type, id) => (dispatch) => {
  dispatch({ type: Constants.DATA_FETCH_SUBMITTED });
  return api()
    .delete(uri)
    .then(() => {
      dispatch({
        type: Constants.DATA_DELETE_SUCCESS,
        payload: Immutable({ type, id }),
      });
    })
    .catch((error) => {
      dispatch({ type: Constants.DATA_FETCH_ERROR, payload: error });
      throw error;
    });
};
<commit_msg>[front] Remove unused import<commit_after>import Immutable from 'seamless-immutable';
import FileSaver from 'file-saver';
import * as Constants from '../constants/ActionTypes';
import { api } from '../Network';

export const submitForm = (formId) => {
  document
    .getElementById(formId)
    .dispatchEvent(new Event('submit', { cancelable: true }));
};

export const fileSave = (uri, filename) => () => api()
  .get(uri, { responseType: 'blob' })
  .then((response) => {
    FileSaver.saveAs(response.data, filename);
  });

export const fileDownload = (uri) => () => api().get(uri, { responseType: 'blob' });

export const simpleCall = (uri) => api().get(uri);

export const getReferential = (schema, uri, noloading) => (dispatch) => {
  if (noloading !== true) {
    dispatch({ type: Constants.DATA_FETCH_SUBMITTED });
  }
  return api(schema)
    .get(uri)
    .then((response) => {
      dispatch({ type: Constants.DATA_FETCH_SUCCESS, payload: response.data });
      return response.data;
    })
    .catch((error) => {
      dispatch({ type: Constants.DATA_FETCH_ERROR, payload: error });
      throw error;
    });
};

export const putReferential = (schema, uri, data) => (dispatch) => {
  dispatch({ type: Constants.DATA_FETCH_SUBMITTED });
  return api(schema)
    .put(uri, data)
    .then((response) => {
      dispatch({ type: Constants.DATA_FETCH_SUCCESS, payload: response.data });
      dispatch({ type: Constants.DATA_UPDATE_SUCCESS, payload: response.data });
      return response.data;
    })
    .catch((error) => {
      dispatch({ type: Constants.DATA_FETCH_ERROR, payload: error });
      throw error;
    });
};

export const postReferential = (schema, uri, data) => (dispatch) => {
  dispatch({ type: Constants.DATA_FETCH_SUBMITTED });
  return api(schema)
    .post(uri, data)
    .then((response) => {
      dispatch({ type: Constants.DATA_FETCH_SUCCESS, payload: response.data });
      return response.data;
    })
    .catch((error) => {
      dispatch({ type: Constants.DATA_FETCH_ERROR, payload: error });
      throw error;
    });
};

export const delReferential = (uri, type, id) => (dispatch) => {
  dispatch({ type: Constants.DATA_FETCH_SUBMITTED });
  return api()
    .delete(uri)
    .then(() => {
      dispatch({
        type: Constants.DATA_DELETE_SUCCESS,
        payload: Immutable({ type, id }),
      });
    })
    .catch((error) => {
      dispatch({ type: Constants.DATA_FETCH_ERROR, payload: error });
      throw error;
    });
};
<|endoftext|>


<commit_before>/*
 * jQuery UI Spinner @VERSION
 *
 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Spinner
 *
 * Depends:
 *  jquery.ui.core.js
 *  jquery.ui.widget.js
 */
(function($) {

// shortcut constants
var hover = 'ui-state-hover',
	active = 'ui-state-active',
	namespace = '.spinner',
	pageModifier = 10;

$.widget('ui.spinner', {
	options: {
		incremental: true,
		max: Number.MAX_VALUE,
		min: -Number.MAX_VALUE,
		numberformat: "n",
		step: 1,
		value: null
	},

	_create: function() {
		this.value(this.options.value !== null ? this.options.value : this.element.val());
		this._draw();
		this._mousewheel();
		this._aria();
	},
	_draw: function() {
		var self = this,
			options = self.options;

		var uiSpinner = self.element
			.addClass('ui-spinner-input')
			.attr('autocomplete', 'off')
			.wrap(self._uiSpinnerHtml())
			.parent()
				// add buttons
				.append(self._buttonHtml())
				// add behaviours
				.hover(function() {
					if (!options.disabled) {
						$(this).addClass(hover);
					}
					self.hovered = true;
				}, function() {
					$(this).removeClass(hover);
					self.hovered = false;
				});

		// TODO: need a better way to exclude IE8 without resorting to $.browser.version
		// fix inline-block issues for IE. Since IE8 supports inline-block we need to exclude it.
		if (!$.support.opacity && uiSpinner.css('display') == 'inline-block' && $.browser.version < 8) {
			uiSpinner.css('display', 'inline');
		}

		this.element
			.bind('keydown'+namespace, function(event) {
				if (self._start(event)) {
					return self._keydown(event);
				}
				return true;
			})
			.bind('keyup'+namespace, function(event) {
				if (self.spinning) {
					self._stop(event);
					self._change(event);
				}
			})
			.bind('focus'+namespace, function() {
				uiSpinner.addClass(active);
				self.focused = true;
			})
			.bind('blur'+namespace, function(event) {
				self.value(self.element.val());
				if (!self.hovered) {
					uiSpinner.removeClass(active);
				}
				self.focused = false;
			});

		// disable spinner if element was already disabled
		if (options.disabled) {
			this.disable();
		}

		// button bindings
		this.buttons = uiSpinner.find('.ui-spinner-button')
			.attr("tabIndex", -1)
			.button()
			.first()
				.removeClass("ui-corner-all")
			.end()
			.last()
				.removeClass("ui-corner-all")
			.end()
			.bind('mousedown', function(event) {
				if (self._start(event) === false) {
					return false;
				}
				self._repeat(null, $(this).hasClass('ui-spinner-up') ? 1 : -1, event);
			})
			.bind('mouseup', function(event) {
				if (self.counter == 1) {
					self._spin(($(this).hasClass('ui-spinner-up') ? 1 : -1) * self.options.step, event);
				}
				if (self.spinning) {
					self._stop(event);
					self._change(event);
				}
			})
			.bind("mouseenter", function() {
				// button will add ui-state-active if mouse was down while mouseleave and kept down
				if ($(this).hasClass("ui-state-active")) {
					if (self._start(event) === false) {
						return false;
					}
					self._repeat(null, $(this).hasClass('ui-spinner-up') ? 1 : -1, event);
				}
			})
			.bind("mouseleave", function() {
				if (self.timer && self.spinning) {
					self._stop(event);
					self._change(event);
				}
			})

		self.uiSpinner = uiSpinner;
	},
	_uiSpinnerHtml: function() {
		return '

';
	},
	_buttonHtml: function() {
		return '▲' +
				'▼';
	},
	_start: function(event) {
		if (!this.spinning && this._trigger('start', event, { value: this.value()}) !== false) {
			if (!this.counter) {
				this.counter = 1;
			}
			this.spinning = true;
			return true;
		}
		return false;
	},
	_spin: function(step, event) {
		if (this.options.disabled) {
			return;
		}
		if (!this.counter) {
			this.counter = 1;
		}

		var newVal = this.value() + step * (this.options.incremental && this.counter > 100
			? this.counter > 200
				? 100
				: 10
			: 1);

		// cancelable
		if (this._trigger('spin', event, { value: newVal }) !== false) {
			this.value(newVal);
			this.counter++;
		}
	},
	_stop: function(event) {
		this.counter = 0;
		if (this.timer) {
			window.clearInterval(this.timer);
		}
		this.element[0].focus();
		this.spinning = false;
		this._trigger('stop', event);
	},
	_change: function(event) {
		this._trigger('change', event);
	},
	_repeat: function(i, steps, event) {
		var self = this;
		i = i || 100;

		if (this.timer) {
			window.clearTimeout(this.timer);
		}

		this.timer = window.setTimeout(function() {
			self._repeat(self.options.incremental && self.counter > 20 ? 20 : i, steps, event);
		}, i);

		self._spin(steps*self.options.step, event);
	},
	_keydown: function(event) {
		var o = this.options,
			KEYS = $.ui.keyCode;

		switch (event.keyCode) {
		case KEYS.UP:
			this._repeat(null, 1, event);
			return false;
		case KEYS.DOWN:
			this._repeat(null, -1, event);
			return false;
		case KEYS.PAGE_UP:
			this._repeat(null, pageModifier, event);
			return false;
		case KEYS.PAGE_DOWN:
			this._repeat(null, -pageModifier, event);
			return false;

		case KEYS.ENTER:
			this.value(this.element.val());
		}

		return true;
	},
	_mousewheel: function() {
		if (!$.fn.mousewheel)
			return;
		var self = this;
		this.element.mousewheel(function(event, delta) {
			delta = ($.browser.opera ? -delta / Math.abs(delta) : delta);
			if (!self._start(event)) {
				return false;
			}
			self._spin((delta > 0 ? 1 : -1) * self.options.step, event);
			if (self.timeout) {
				window.clearTimeout(self.timeout);
			}
			self.timeout = window.setTimeout(function() {
				if (self.spinning) {
					self._stop(event);
					self._change(event);
				}
			}, 50);
			event.preventDefault();
		});
	},
	value: function(newVal) {
		if (!arguments.length) {
			return this._parse(this.element.val());
		}
		this._setOption('value', newVal);
	},
	_getData: function(key) {
		switch (key) {
			case 'min':
			case 'max':
			case 'step':
				return this['_'+key]();
				break;
		}
		return this.options[key];
	},
	_setOption: function(key, value) {
		if (key == 'value') {
			value = this._parse(value);
			if (value < this.options.min) {
				value = this.options.min;
			}
			if (value > this.options.max) {
				value = this.options.max;
			}
		}
		$.Widget.prototype._setOption.call( this, key, value );
		this._afterSetData(key, value);
	},
	_afterSetData: function(key, value) {
		switch(key) {
			case 'max':
			case 'min':
			case 'step':
				if (value != null) {
					// write attributes back to element if original exist
					if (this.element.attr(key)) {
						this.element.attr(key, value);
					}
				}
				this._aria();
				break;
			case 'value':
				this._format(this._parse(this.options.value));
				break;
		}
	},
	_aria: function() {
		this.uiSpinner
				.attr('aria-valuemin', this.options.min)
				.attr('aria-valuemax', this.options.max)
				.attr('aria-valuenow', this.value());
	},

	_parse: function(val) {
		var input = val;
		if (typeof val == 'string') {
			// special case for currency formatting until Globalization handles currencies
			if (this.options.numberformat == "C" && window.Globalization) {
				// parseFloat should accept number format, including currency
				var culture = Globalization.culture || Globalization.cultures['default'];
				val = val.replace(culture.numberFormat.currency.symbol, "");
			}
			val = window.Globalization ? Globalization.parseFloat(val) : +val;
		}
		console.log("input", input, "parsed", val)
		return isNaN(val) ? null : val;
	},
	_format: function(num) {
		this.element.val( window.Globalization ? Globalization.format(num, this.options.numberformat) : num );
	},

	destroy: function() {
		if ($.fn.mousewheel) {
			this.element.unmousewheel();
		}

		this.element
			.removeClass('ui-spinner-input')
			.removeAttr('disabled')
			.removeAttr('autocomplete')
			.removeData('spinner')
			.unbind(namespace);

		this.uiSpinner.replaceWith(this.element);
	},
	enable: function() {
		this.element
			.removeAttr('disabled')
			.siblings()
				.removeAttr('disabled')
			.parent()
				.removeClass('ui-spinner-disabled ui-state-disabled');
		this.options.disabled = false;
	},
	disable: function() {
		this.element
			.attr('disabled', true)
			.siblings()
				.attr('disabled', true)
			.parent()
				.addClass('ui-spinner-disabled ui-state-disabled');
		this.options.disabled = true;
	},
	stepUp: function(steps) {
		this._spin((steps || 1) * this.options.step, null);
		return this;
	},
	stepDown: function(steps) {
		this._spin((steps || 1) * -this.options.step, null);
		return this;
	},
	pageUp: function(pages) {
		return this.stepUp((pages || 1) * this.options.page);
	},
	pageDown: function(pages) {
		return this.stepDown((pages || 1) * this.options.page);
	},

	widget: function() {
		return this.uiSpinner;
	}
});

})(jQuery);
<commit_msg>Slider: Simplifying mousewheel binding, remove Opera workaround<commit_after>/*
 * jQuery UI Spinner @VERSION
 *
 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Spinner
 *
 * Depends:
 *  jquery.ui.core.js
 *  jquery.ui.widget.js
 */
(function($) {

// shortcut constants
var hover = 'ui-state-hover',
	active = 'ui-state-active',
	namespace = '.spinner',
	pageModifier = 10;

$.widget('ui.spinner', {
	options: {
		incremental: true,
		max: Number.MAX_VALUE,
		min: -Number.MAX_VALUE,
		numberformat: "n",
		step: 1,
		value: null
	},

	_create: function() {
		this.value(this.options.value !== null ? this.options.value : this.element.val());
		this._draw();
		this._mousewheel();
		this._aria();
	},
	_draw: function() {
		var self = this,
			options = self.options;

		var uiSpinner = self.element
			.addClass('ui-spinner-input')
			.attr('autocomplete', 'off')
			.wrap(self._uiSpinnerHtml())
			.parent()
				// add buttons
				.append(self._buttonHtml())
				// add behaviours
				.hover(function() {
					if (!options.disabled) {
						$(this).addClass(hover);
					}
					self.hovered = true;
				}, function() {
					$(this).removeClass(hover);
					self.hovered = false;
				});

		// TODO: need a better way to exclude IE8 without resorting to $.browser.version
		// fix inline-block issues for IE. Since IE8 supports inline-block we need to exclude it.
		if (!$.support.opacity && uiSpinner.css('display') == 'inline-block' && $.browser.version < 8) {
			uiSpinner.css('display', 'inline');
		}

		this.element
			.bind('keydown'+namespace, function(event) {
				if (self._start(event)) {
					return self._keydown(event);
				}
				return true;
			})
			.bind('keyup'+namespace, function(event) {
				if (self.spinning) {
					self._stop(event);
					self._change(event);
				}
			})
			.bind('focus'+namespace, function() {
				uiSpinner.addClass(active);
				self.focused = true;
			})
			.bind('blur'+namespace, function(event) {
				self.value(self.element.val());
				if (!self.hovered) {
					uiSpinner.removeClass(active);
				}
				self.focused = false;
			});

		// disable spinner if element was already disabled
		if (options.disabled) {
			this.disable();
		}

		// button bindings
		this.buttons = uiSpinner.find('.ui-spinner-button')
			.attr("tabIndex", -1)
			.button()
			.first()
				.removeClass("ui-corner-all")
			.end()
			.last()
				.removeClass("ui-corner-all")
			.end()
			.bind('mousedown', function(event) {
				if (self._start(event) === false) {
					return false;
				}
				self._repeat(null, $(this).hasClass('ui-spinner-up') ? 1 : -1, event);
			})
			.bind('mouseup', function(event) {
				if (self.counter == 1) {
					self._spin(($(this).hasClass('ui-spinner-up') ? 1 : -1) * self.options.step, event);
				}
				if (self.spinning) {
					self._stop(event);
					self._change(event);
				}
			})
			.bind("mouseenter", function() {
				// button will add ui-state-active if mouse was down while mouseleave and kept down
				if ($(this).hasClass("ui-state-active")) {
					if (self._start(event) === false) {
						return false;
					}
					self._repeat(null, $(this).hasClass('ui-spinner-up') ? 1 : -1, event);
				}
			})
			.bind("mouseleave", function() {
				if (self.timer && self.spinning) {
					self._stop(event);
					self._change(event);
				}
			})

		self.uiSpinner = uiSpinner;
	},
	_uiSpinnerHtml: function() {
		return '

';
	},
	_buttonHtml: function() {
		return '▲' +
				'▼';
	},
	_start: function(event) {
		if (!this.spinning && this._trigger('start', event, { value: this.value()}) !== false) {
			if (!this.counter) {
				this.counter = 1;
			}
			this.spinning = true;
			return true;
		}
		return false;
	},
	_spin: function(step, event) {
		if (this.options.disabled) {
			return;
		}
		if (!this.counter) {
			this.counter = 1;
		}

		var newVal = this.value() + step * (this.options.incremental && this.counter > 100
			? this.counter > 200
				? 100
				: 10
			: 1);

		// cancelable
		if (this._trigger('spin', event, { value: newVal }) !== false) {
			this.value(newVal);
			this.counter++;
		}
	},
	_stop: function(event) {
		this.counter = 0;
		if (this.timer) {
			window.clearInterval(this.timer);
		}
		this.element[0].focus();
		this.spinning = false;
		this._trigger('stop', event);
	},
	_change: function(event) {
		this._trigger('change', event);
	},
	_repeat: function(i, steps, event) {
		var self = this;
		i = i || 100;

		if (this.timer) {
			window.clearTimeout(this.timer);
		}

		this.timer = window.setTimeout(function() {
			self._repeat(self.options.incremental && self.counter > 20 ? 20 : i, steps, event);
		}, i);

		self._spin(steps*self.options.step, event);
	},
	_keydown: function(event) {
		var o = this.options,
			KEYS = $.ui.keyCode;

		switch (event.keyCode) {
		case KEYS.UP:
			this._repeat(null, 1, event);
			return false;
		case KEYS.DOWN:
			this._repeat(null, -1, event);
			return false;
		case KEYS.PAGE_UP:
			this._repeat(null, pageModifier, event);
			return false;
		case KEYS.PAGE_DOWN:
			this._repeat(null, -pageModifier, event);
			return false;

		case KEYS.ENTER:
			this.value(this.element.val());
		}

		return true;
	},
	_mousewheel: function() {
		var self = this;
		this.element.bind("mousewheel", function(event, delta) {
			if (!self._start(event)) {
				return false;
			}
			self._spin((delta > 0 ? 1 : -1) * self.options.step, event);
			if (self.timeout) {
				window.clearTimeout(self.timeout);
			}
			self.timeout = window.setTimeout(function() {
				if (self.spinning) {
					self._stop(event);
					self._change(event);
				}
			}, 50);
			event.preventDefault();
		});
	},
	value: function(newVal) {
		if (!arguments.length) {
			return this._parse(this.element.val());
		}
		this._setOption('value', newVal);
	},
	_getData: function(key) {
		switch (key) {
			case 'min':
			case 'max':
			case 'step':
				return this['_'+key]();
				break;
		}
		return this.options[key];
	},
	_setOption: function(key, value) {
		if (key == 'value') {
			value = this._parse(value);
			if (value < this.options.min) {
				value = this.options.min;
			}
			if (value > this.options.max) {
				value = this.options.max;
			}
		}
		$.Widget.prototype._setOption.call( this, key, value );
		this._afterSetData(key, value);
	},
	_afterSetData: function(key, value) {
		switch(key) {
			case 'max':
			case 'min':
			case 'step':
				if (value != null) {
					// write attributes back to element if original exist
					if (this.element.attr(key)) {
						this.element.attr(key, value);
					}
				}
				this._aria();
				break;
			case 'value':
				this._format(this._parse(this.options.value));
				break;
		}
	},
	_aria: function() {
		this.uiSpinner
				.attr('aria-valuemin', this.options.min)
				.attr('aria-valuemax', this.options.max)
				.attr('aria-valuenow', this.value());
	},

	_parse: function(val) {
		var input = val;
		if (typeof val == 'string') {
			// special case for currency formatting until Globalization handles currencies
			if (this.options.numberformat == "C" && window.Globalization) {
				// parseFloat should accept number format, including currency
				var culture = Globalization.culture || Globalization.cultures['default'];
				val = val.replace(culture.numberFormat.currency.symbol, "");
			}
			val = window.Globalization ? Globalization.parseFloat(val) : +val;
		}
		console.log("input", input, "parsed", val)
		return isNaN(val) ? null : val;
	},
	_format: function(num) {
		this.element.val( window.Globalization ? Globalization.format(num, this.options.numberformat) : num );
	},

	destroy: function() {
		if ($.fn.mousewheel) {
			this.element.unmousewheel();
		}

		this.element
			.removeClass('ui-spinner-input')
			.removeAttr('disabled')
			.removeAttr('autocomplete')
			.removeData('spinner')
			.unbind(namespace);

		this.uiSpinner.replaceWith(this.element);
	},
	enable: function() {
		this.element
			.removeAttr('disabled')
			.siblings()
				.removeAttr('disabled')
			.parent()
				.removeClass('ui-spinner-disabled ui-state-disabled');
		this.options.disabled = false;
	},
	disable: function() {
		this.element
			.attr('disabled', true)
			.siblings()
				.attr('disabled', true)
			.parent()
				.addClass('ui-spinner-disabled ui-state-disabled');
		this.options.disabled = true;
	},
	stepUp: function(steps) {
		this._spin((steps || 1) * this.options.step, null);
		return this;
	},
	stepDown: function(steps) {
		this._spin((steps || 1) * -this.options.step, null);
		return this;
	},
	pageUp: function(pages) {
		return this.stepUp((pages || 1) * this.options.page);
	},
	pageDown: function(pages) {
		return this.stepDown((pages || 1) * this.options.page);
	},

	widget: function() {
		return this.uiSpinner;
	}
});

})(jQuery);
<|endoftext|>