<commit_before>/*
 *  (c) 3DaGoGo, Inc. (product@astroprint.com)
 *
 *  Distributed under the GNU Affero General Public License http://www.gnu.org/licenses/agpl.html
 */

/*############################
## TEMPERATURE VIEW CONTROL ##
##############################*/

// Dependency: /models/printerprofile.js, /widgets/tempbarview.js
// this object is being extended by the sub part 'TempView'

/* Comment-change#1 */
var TempBarVerticalView = TempBarView.extend({
  containerDimensions: null,
  scale: null, // array of the values coming from the printer profile
  type: null,
  dragging: false,
  events: _.extend(TempBarView.prototype.events, {
    /*
    * We have two different events here,
    * 1) When the .temp-bar is clicked
    * 2) When the off button is pressed
    */
    'click .temp-bar': 'onClicked',
    'click button.temp-off': 'turnOff'
  }),
  // this function is for sliding the 'temp-target' on the temp-bar
  // this part will not be included in the new UI but a progress bar
  // showing the increasing temp will be needed to display
  setHandle: function(value){

    // console.log("setHandle function is being called");

    if (!this.dragging) {
      var position = this._temp2px(value);
      var handle = this.$el.find('.temp-target');

      // temp-target will move immediately when the value of temp is added
      handle.css({transition: 'top 0.5s'});
      handle.css({top: position + 'px'});

      // 'target-value' is the field where we input the temperature value
      handle.find('span.target-value').text(value);
      setTimeout(function() {
        handle.css({transition: ''});
      }, 800);
    }
  },
  onTouchMove: function(e)
  {
    // console.log("onTouchMove functino is called");
    if (this.dragging) {
      e.preventDefault();
      e.stopPropagation();
      var target = this.$('.temp-target');

      if (e.type == 'mousemove') {
        var pageY = e.originalEvent.pageY;
      } else {
        var pageY = e.originalEvent.changedTouches[0].clientY + $(document).scrollTop();
      }

      var newTop = pageY - this.containerDimensions.top - target.innerHeight()/2.0;

      newTop = Math.min(Math.max(newTop, 0), this.containerDimensions.maxTop );

      target.css({top: newTop+'px'});
      target.find('span.target-value').text(this._px2temp(newTop));
    }
  },

  // callback function for handling the 'click' event on the 'temp-bar'
  onClicked: function(e)
  {

    // console.log("onClicked function is called");
    e.preventDefault();
    var target = this.$el.find('.temp-target');
    // console.log(target);
    var newTop = e.pageY - this.containerDimensions.top - target.innerHeight()/2.0;

    newTop = Math.min( Math.max(newTop, 0), this.containerDimensions.maxTop );
    // console.log(newTop);

    var temp = this._px2temp(newTop);

    this.setHandle(temp);
    this._sendToolCommand('target', this.type, temp);
  },
  onResize: function()
  {
    // console.log("onResize function is called");
    var container = this.$el.find('.temp-bar');
    var handle = container.find('.temp-target');
    var label = container.find('label');

    var height = container.height();
    var maxTop = height - handle.innerHeight() - label.innerHeight();

    this.containerDimensions = {
      top: container.offset().top,
      height: height,
      maxTop: maxTop,
      px4degree: maxTop / (this.scale[1] - this.scale[0])
    };
  },

  // this function will render the actual increasing temperature
  renderTemps: function(actual, target)
  {
    // console.log("renderTemps is called");
    var handleHeight = this.$el.find('.temp-target').innerHeight();

    if (actual !== null) {
      // changing the value of rising temp on the 'current-temp-top' and displaying that
      this.$el.find('.current-temp-top').html(Math.round(actual)+'°');

      // moving the horizontal bar based on the rising temperature
      // In new UI we will need to show this part as a progress bar
      this.$el.find('.current-temp').css({top: (this._temp2px(actual) + handleHeight/2 )+'px'});
    }

    if (target !== null) {
      this.setHandle(Math.min(Math.round(target), this.scale[1]));
    }
  },

  /*
  function for getting the values in pixel to move the slider to the same amount
  */
  _temp2px: function(temp){
    // console.log("_temp2px is called");
    // console.log(temp);
    var px = temp * this.containerDimensions.px4degree;

    return this.containerDimensions.maxTop - px;
  },

  /*
  this function will convert the pixel to the temperature
  */
  _px2temp: function(px)
  {
    // console.log("_px2temp is called");
    return Math.round( ( (this.containerDimensions.maxTop - px) / this.containerDimensions.px4degree ) );
  }
});

// this object is controlling the temperature of bed and nozzle
// Basically this view is reponsible for preheating process

/* Comment-change#1 */
var TempView = Backbone.View.extend({
  el: '#temp-control',
  nozzleTempBar: null,
  bedTempBar: null,
  initialize: function()
  {
    // creating the new instance for controlling the nozzle temp-bar
    this.nozzleTempBar = new TempBarVerticalView({
      scale: [0, app.printerProfile.get('max_nozzle_temp')],
      el: this.$el.find('.temp-control-cont.nozzle'),
      type: 'tool0'
    });

    // creating the new instance for controlling the bed temp-bar
    this.bedTempBar = new TempBarVerticalView({
      scale: [0, app.printerProfile.get('max_bed_temp')],
      el: this.$el.find('.temp-control-cont.bed'),
      type: 'bed'
    });

    this.render();
  },
  render: function()
  {
    // Referencing the 'models/printerprofile.js' file to get the data
    var profile = app.printerProfile.toJSON();

    // console.log(profile);
    // console.log(this);

    // here we are setting the nozzleTempBar temperature to the max-nozzle-temp
    // from the 'printerprofile'
    this.nozzleTempBar.setMax(profile.max_nozzle_temp);

    if (profile.heated_bed) {
      // setting the bed temperature to the max-bed-temp form the printerprofile
      this.bedTempBar.setMax(profile.max_bed_temp);
      this.bedTempBar.$el.removeClass('disabled');
    } else {
      this.bedTempBar.$el.addClass('disabled');
    }
  },

  // this function is having dependecies with: "router.js"
  resetBars: function()
  {
    this.nozzleTempBar.onResize();
    this.bedTempBar.onResize();
  },

  // this function is not having dependencies to outer js file
  // this function is responsible for setting the nozzle and bed temperature
  updateBars: function(value)
  {
    if (value.extruder) {
      this.nozzleTempBar.setTemps(value.extruder.actual, value.extruder.target);
    }

    if (value.bed) {
      this.bedTempBar.setTemps(value.bed.actual, value.bed.target);
    }
  }
});

/*#####################
## XY-Z CONTROL PANEL #
#######################*/

// this 'view' is reponsible for setting the distance to move when the extruder moves
// based on the click on the control panel in X, Y and Z directions correspondingly

/*
  Currently we are selecting a particular value and for all the directions this value
  be set. (5mm slelected means: click X --move 5 mm, click Y --move 5mm, click Z --move 5mm)

  In the new UI, we want to set the different values to the different directions
*/
// var DistanceControl = Backbone.View.extend({
//   el: '#distance-control',
//   selected: 10, // this is the default value which we have set initially. we can change this
//   events: {
//     'click button': 'selectDistance' // this is the function which will be envoked on the click event
//   },
//   selectDistance: function(e)
//   {
//     var el = $(e.currentTarget); // this will get the target button which we hit
//     console.log(el);
//     // this is removing the 'success' from other and adding the secondary class to the other
//     this.$el.find('.success').removeClass('success').addClass('secondary');
//     el.addClass('success').removeClass('secondary'); // then again adding the 'success' to itself

//     // here we are setting the value of 'selected' property based on the value choosed
//     this.selected = el.attr('data-value');

//     console.log(this.selected);
//   }
// });

// this 'view' is reponsible for the movents on x,y and z directions
// the subviews are 'XYControlView' and 'ZControlView' which are
// extending this view
// var MovementControlView = Backbone.View.extend({
//   distanceControl: null,
//   printerProfile: null,
//   initialize: function(params)
//   {
//     // console.log("I got a call for initialization");
//     console.log(params);
//     this.distanceControl = params.distanceControl;
//     // console.log(this.distanceControl);
//   },

//   // here we are sending a POST request whenever a jogging button in clicked
//   sendJogCommand: function(axis, multiplier, distance)
//   {
//     if (typeof distance === "undefined")
//       distance = 10;

//     var data = {
//       "command": "jog"
//     }
//     data[axis] = distance * multiplier;

//     $.ajax({
//       url: API_BASEURL + "printer/printhead",
//       type: "POST",
//       dataType: "json",
//       contentType: "application/json; charset=UTF-8",
//       data: JSON.stringify(data)
//     });
//   },

//   // here we are sending the POST request whenever a home button in clicked
//   sendHomeCommand: function(axis)
//   {
//     var data = {
//       "command": "home",
//       "axes": axis
//     }

//     $.ajax({
//       url: API_BASEURL + "printer/printhead",
//       type: "POST",
//       dataType: "json",
//       contentType: "application/json; charset=UTF-8",
//       data: JSON.stringify(data)
//     });
//   }
// });

// this 'view' is reponsible to handle the click events on the xy controller
// var XYControlView = MovementControlView.extend({
//   el: '#xy-controls',
//   events: {
//     'click .control_btn_x_plus': 'xPlusTapped',
//     'click .control_btn_x_minus': 'xMinusTapped',
//     'click .control_btn_y_plus': 'yPlusTapped',
//     'click .control_btn_y_minus': 'yMinusTapped',
//     'click .home_z': 'homeTapped'
//   },

//   // call back functions for taking care of the click events on the control keys
//   xPlusTapped: function()
//   {
//     console.log(this);
//     // console.log(this.distanceControl.selected);
//     this.sendJogCommand('x', 1, this.distanceControl.selected);
//   },
//   xMinusTapped: function()
//   {
//     this.sendJogCommand('x', -1, this.distanceControl.selected);
//   },
//   yPlusTapped: function()
//   {
//     this.sendJogCommand('y', 1, this.distanceControl.selected);
//   },
//   yMinusTapped: function()
//   {
//     this.sendJogCommand('y', -1, this.distanceControl.selected);
//   },
//   homeTapped: function()
//   {
//     if (!app.socketData.get('paused')) {
//       this.sendHomeCommand(['x', 'y']);
//     }
//   }
// });

// this view is responsible to handle the click events on the z-control of printer
// var ZControlView = MovementControlView.extend({
//   el: '#z-controls',
//   events: {
//     'click .control_btn_z_plus': 'zPlusTapped',
//     'click .control_btn_z_minus': 'zMinusTapped',
//     'click .home_z': 'homeTapped'
//   },
//   zPlusTapped: function()
//   {
//     this.sendJogCommand('z', 1, this.distanceControl.selected);
//   },
//   zMinusTapped: function()
//   {
//     this.sendJogCommand('z', -1 , this.distanceControl.selected);
//   },
//   homeTapped: function()
//   {
//     if (!app.socketData.get('paused')) {
//       this.sendHomeCommand('z');
//     }
//   }
// });

/*#######################
## EXTRUSION CONTROL ####
#########################*/

// this 'view' is responsible for the 'extrusion' processs
// We will need to map the below JS with our new UI

/* Comment-change#1 */
// var ExtrusionControlView = Backbone.View.extend({
//   el: '#extrusion-control',
//   template: null,
//   events: {
//     /* below 2 events will be fired when the user clicks the extrude or retract*/
//     'click .extrude': 'extrudeTapped',
//     'click .retract': 'retractTapped',
//     'change .extrusion-length': 'lengthChanged',
//     'change .extrusion-speed': 'speedChanged',
//     'keydown input.back-to-select': 'onKeyDownBackToSelect'
//   },
//   initialize: function()
//   {
//     // getting the subtemplate to be attached in the parent template
//     this.template = _.template( this.$("#extruder-switch-template").html() );
//     this.render(); // calling the 'render' function of the View
//   },
//   render: function()
//   {
//     // getting the printer profile
//     var printer_profile = app.printerProfile.toJSON();

//     // attaching the child template to the parent template
//     this.$('.row.extruder-switch').html(this.template());

//     if (printer_profile.extruder_count > 1) {
//       /*
//       * if extruder count is more than 1, then we are going to add
//       * another event to the event list and also added the event handler function
//       * "extruderChanged"
//       */
//       this.events['change .extruder-number'] = "extruderChanged";
//     }

//     this.delegateEvents(this.events);
//   },

//   /* Below function is the callback when the extrude button is tapped */
//   extrudeTapped: function()
//   {
//     if (this._checkAmount()) { // checking the value of extrude amount
//       // sending the POST request to the server for starting the extrusion
//       this._sendExtrusionCommand(1);
//     }
//   },

//   /* Below function is the callback when the retract button is tapped */
//   retractTapped: function()
//   {
//     if (this._checkAmount()) { // checking the value of the extrude amount
//       // sending the POST request to the server for starting the retraction
//       this._sendExtrusionCommand(-1);
//     }
//   },

//   // This function is reponsible to get the value from the UI if the
//   // Other option is selected for AMOUT
//   lengthChanged: function(e)
//   {
//     var elem = $(e.target);
//     if (elem.val() == 'other') {
//       elem.addClass('hide');
//       this.$('.other-length').removeClass('hide').find('input').focus().select();
//     } else {
//       this.$('input[name="extrusion-length"]').val(elem.val());
//     }
//   },

//   // if Other option is selected for SPEED
//   speedChanged: function(e)
//   {
//     var elem = $(e.target);

//     if (elem.val() == 'other') {
//       elem.addClass('hide');
//       this.$('.other-speed').removeClass('hide').find('input').focus().select();
//     } else {
//       this.$('input[name="extrusion-speed"]').val(elem.val());
//     }
//   },

//   /* Callback function in case we have more than 1 extruder */
//   extruderChanged: function(e)
//   {
//     this._sendChangeToolCommand($(e.target).val())
//   },

//   /*
//     In case while selecting the 'Other' options from the SPEED or AMOUNT, we didn't enter
//     any custom value and pressed the ESC key, then the below function is responsible to
//     set the things back to the default.
//   */
//   onKeyDownBackToSelect: function(e)
//   {
//     if (e.keyCode == 27) { //ESC Key
//       var target = $(e.currentTarget);
//       console.log(target);
//       var select = target.closest('div.select-with-text').find('select');

//       //Find out the default value. Middle one
//       var defaultValue = select.find('option[default]').val();

//       target.closest('.row').addClass('hide');
//       target.val(defaultValue);
//       select.removeClass('hide').val(defaultValue);
//     }
//   },

//   // function to send the POST request when tool changes
//   _sendChangeToolCommand: function(tool)
//   {
//     var data = {
//       command: "select",
//       tool: 'tool'+tool
//     }

//     $.ajax({
//       url: API_BASEURL + "printer/tool",
//       type: "POST",
//       dataType: "json",
//       contentType: "application/json; charset=UTF-8",
//       data: JSON.stringify(data)
//     });
//   },
//   _checkAmount: function()
//   {
//     // this is checking the value of exturedAmount from the input
//     return !isNaN(this.$el.find('input[name="extrusion-length"]').val());
//   },

//   /* This function will send the POST request to the server for starting
//   the extrusion process
//   */
//   _sendExtrusionCommand: function(direction)
//   {
//     // this is the data to be send to the server in the POST request
//     var data = {
//       command: "extrude",
//       amount: parseFloat(this.$('input[name="extrusion-length"]').val() * direction),
//       speed: parseFloat(this.$('input[name="extrusion-speed"]').val())
//     }

//     // this value will only come if there will be more than 1 extruder
//     var extruder = this.$('select.extruder-number').val();

//     if (extruder) {
//       data['tool'] = 'tool'+extruder;
//     }

//     $.ajax({
//       url: API_BASEURL + "printer/tool",
//       type: "POST",
//       dataType: "json",
//       contentType: "application/json; charset=UTF-8",
//       data: JSON.stringify(data)
//     });
//   }
// });

var ExtrusionControlView = Backbone.View.extend({
  el: "#extrusion-control",
  initialize: function() {},
  render: function() {}
});

/*###############
## FAN CONTROL ##
#################*/

// this 'view' is responsible for the 'Fan Controling part'
// As of now this part is not included in the new UI

/* Comment-change#1 */
var FanControlView = Backbone.View.extend({
  el: '#temp-control .fan-control',
  events: {
    'click button.fan-on': "fanOn",
    'click button.fan-off': "fanOff"
  },
  fanOn: function()
  {
    this._setFanSpeed(255);
    this.$('.fan_icon').addClass('animate-spin');
  },
  fanOff: function()
  {
    this._setFanSpeed(0);
    this.$('.fan_icon').removeClass('animate-spin');
  },
  _setFanSpeed: function(speed)
  {
    var data = {
      command: "set",
      tool: 0,
      speed: speed
    }

    $.ajax({
      url: API_BASEURL + "printer/fan",
      type: "POST",
      dataType: "json",
      contentType: "application/json; charset=UTF-8",
      data: JSON.stringify(data)
    });
  }
});

// This 'view' will initialize all the parent views in the
// 'control-view' section
// this 'ControlView' ConstructorFunction will be called through the 'router.js' file
var ControlView = Backbone.View.extend({
  el: '#control-view',
  events: {
    'click .back-to-print button': 'resumePrinting',
    'show': 'render'
  }, // 'back-to-print' class is used to resume the printing
  template: null,
  tempView: null,
  distanceControl: null,
  xyControlView: null,
  zControlView: null,
  extrusionView: null,
  fanView: null,
  initialize: function(options)
  {
    /*
      Since the views will access the DOM, we have to initialize as well as
      render the templates before initializing any other instances of different
      views.
    */

    // here we have created the new instances for all the views on the #control-page

    // this.tempView = new TempView(); /* Comment-change#1 */
    // this.distanceControl = new DistanceControl();
    // this.xyControlView = new XYControlView({distanceControl: this.distanceControl});
    // this.zControlView = new ZControlView({distanceControl: this.distanceControl});
    // this.extrusionView = new ExtrusionControlView(); /* Comment-change#1 */
    // this.fanView = new FanControlView(); /* Comment-change#1 */

    // this function is listening for the 'temps' to be changed, and once it changes
    // it use to call the 'updateTemps' function and that ultimately call the
    // 'updateBars' function to display the change in temperature
    this.listenTo(app.socketData, 'change:temps', this.updateTemps);
    this.listenTo(app.socketData, 'change:paused', this.onPausedChanged);
  },

  // this is responsible for updating the temp on the bars when the panel is initialized
  // this function is the call back function to run every time whenver the 'temps' property
  // in socketData use to change
  updateTemps: function(s, value)
  {
    console.log(s);
    console.log(value)
    if (!this.$el.hasClass('hide')) {
      this.tempView.updateBars(value);
    }
  },

  // this is the render function for the controlView. It will initialized all the
  // render function for the child views
  render: function()
  {

    this.onPausedChanged(app.socketData, app.socketData.get('paused'));

    // this.extrusionView.render(); /* Comment-change#1 */
    // this.tempView.render(); /* Comment-change#1 */
    this.changeTemplate();
  },
  // function for checking validating and rendering the selected template
  changeTemplate: function() {

    /* Added conditions to render the particular Utility based on the click from Utility page */

    if (this.buttonName === "Manual_Controls_Button") {

      this.setTemplate(this.$("#xyz-controls-template").html(), null);
      this.distanceControl = new DistanceControl();
      this.xyControlView = new XYControlView({distanceControl: this.distanceControl});
      this.zControlView = new ZControlView({distanceControl: this.distanceControl});

    } else if (this.buttonName === "Filament_Button"){

      this.setTemplate(this.$("#filament-template").html(), {profile: app.printerProfile.toJSON()});
      this.extrusionView = new ExtrusionControlView();

    } else if (this.buttonName === "Level_Bed_Button") {

      this.setTemplate( "<h1 align='center'> No template for the Automatic Bed Levling </h1>", null);

    } else {

      this.setTemplate( this.$("#pre-heat-template").html(), null);
      this.tempView = new TempView();
      this.fanView = new FanControlView();
    }

    /* Initializing the Views when the selected template has been rendered */

  },
  /*
    function to set the template of Control View.
    The 'params' argument is the JSON object which we want to use in the template/child template.
    We will need to pass the model object in the parent object itself if we want to catch the
    values in the 'child' template
  */

  setTemplate: function(template, params) {
    this.template = _.template(template);
    this.$('#manual-container').html(this.template(params));
  },
  resumePrinting: function(e)
  {
    app.setPrinting();
    app.router.navigate("printing", {replace: true, trigger: true});
    app.router.printingView.togglePausePrint(e);

    this.$el.addClass('hide');
  },
  onPrintingProgressChanged: function(model, printingProgress)
  {
    var el = this.$('.back-to-print .filename');

    if (printingProgress && printingProgress.printFileName && printingProgress.printFileName != el.text()) {
      el.text(printingProgress.printFileName)
    }
  },
  onPausedChanged: function(model, paused)
  {
    if (paused) {
      this.listenTo(app.socketData, 'change:printing_progress', this.onPrintingProgressChanged);
      this.$el.addClass('print-paused');
    } else {
      this.stopListening(app.socketData, 'change:printing_progress');

      if (app.socketData.get('printing')) {
        app.router.navigate("printing", {replace: true, trigger: true});
      } else {
        this.$el.removeClass('print-paused');
      }
    }
  }
});
<commit_msg>Refactored the code<commit_after>/****************************************
* Code edited by Kanishka Mohan Madhuni *
*****************************************/

var TempBarVerticalView = TempBarView.extend({
  containerDimensions: null,
  scale: null, // array of the values coming from the printer profile
  type: null,
  dragging: false,
  // adding 'value' property to hold the object when the temperature updates
  value: null,
  events: _.extend(TempBarView.prototype.events, {
    'click button.temp-off': 'turnOff'
  }),
  setHandle: function(value){
    if (!this.dragging) {
      var handle = this.$el.find('.temp-target');
      handle.find('span.target-value').text(value);
    }
  },
  renderTemps: function(actual, target){
    if (actual !== null) {
      this.$el.find('.current-temp-top').html(Math.round(actual)+'°');
    }
    if (target !== null) {
      this.setHandle(Math.min(Math.round(target), this.scale[1]));
    }
  },
});

var TempView = Backbone.View.extend({
  el: '#temp-control',
  nozzleTempBar: null,
  bedTempBar: null,
  initialize: function()
  {
    // creating the new instance for controlling the nozzle temp-bar
    this.nozzleTempBar = new TempBarVerticalView({
      scale: [0, app.printerProfile.get('max_nozzle_temp')],
      el: this.$el.find('.temp-control-cont.nozzle'),
      type: 'tool0'
    });

    // creating the new instance for controlling the bed temp-bar
    this.bedTempBar = new TempBarVerticalView({
      scale: [0, app.printerProfile.get('max_bed_temp')],
      el: this.$el.find('.temp-control-cont.bed'),
      type: 'bed'
    });

    this.render();
  },
  render: function(){
    var profile = app.printerProfile.toJSON();

    // here we are setting the nozzleTempBar temperature to the max-nozzle-temp from the 'printerProfile'
    this.nozzleTempBar.setMax(profile.max_nozzle_temp);

    if (profile.heated_bed) {
      // setting the bed temperature to the max-bed-temp form the printerprofile
      this.bedTempBar.setMax(profile.max_bed_temp);
      this.bedTempBar.$el.removeClass('disabled');
    } else {
      this.bedTempBar.$el.addClass('disabled');
    }
  },
  // this function is responsible for setting the nozzle and bed temperature
  updateBars: function(value)
  {
    if (value.extruder) {
      this.nozzleTempBar.setTemps(value.extruder.actual, value.extruder.target);
    }

    if (value.bed) {
      this.bedTempBar.setTemps(value.bed.actual, value.bed.target);
    }
  }
});

var ExtrusionControlView = Backbone.View.extend({
  el: "#extrusion-control",
  initialize: function() {},
  render: function() {}
});

// This 'view' will initialize all the parent views in the
// 'control-view' section
// this 'ControlView' ConstructorFunction will be called through the 'router.js' file
var ControlView = Backbone.View.extend({
  el: '#control-view',
  events: {
    'click .back-to-print button': 'resumePrinting',
    'show': 'render'
  }, // 'back-to-print' class is used to resume the printing
  template: null,
  tempView: null,
  distanceControl: null,
  xyControlView: null,
  zControlView: null,
  extrusionView: null,
  fanView: null,
  initialize: function(options){
    this.listenTo(app.socketData, 'change:temps', this.updateTemps);
    this.listenTo(app.socketData, 'change:paused', this.onPausedChanged);
  },
  updateTemps: function(s, value){
    this.value = value;
    if (!this.$el.hasClass('hide')) {
      this.tempView.updateBars(value);
    }
  },
  render: function(){
    this.onPausedChanged(app.socketData, app.socketData.get('paused'));
    this.changeTemplate();
  },
  // function for checking validating and rendering the selected template
  changeTemplate: function() {
    /* Added conditions to render the particular Utility based on the click from Utility page */

    if (this.buttonName === "Manual_Controls_Button") {

      this.setTemplate(this.$("#xyz-controls-template").html(), null);
      this.distanceControl = new DistanceControl();
      this.xyControlView = new XYControlView({distanceControl: this.distanceControl});
      this.zControlView = new ZControlView({distanceControl: this.distanceControl});

    } else if (this.buttonName === "Filament_Button"){

      this.setTemplate(this.$("#filament-template").html(), {profile: app.printerProfile.toJSON()});
      this.extrusionView = new ExtrusionControlView();

    } else if (this.buttonName === "Level_Bed_Button") {

      this.setTemplate( "<h1 align='center'> No template for the Automatic Bed Levling </h1>", null);

    } else {

      this.setTemplate( this.$("#pre-heat-template").html(), null);
      this.tempView = new TempView();
    }
  },
  /*
    function to set the template of Control View.
    The 'params' argument is the JSON object which we want to use in the template/child template.
    We will need to pass the model object in the parent object itself if we want to catch the
    values in the 'child' template
  */
  setTemplate: function(template, params) {
    this.template = _.template(template);
    this.$('#manual-container').html(this.template(params));
  },
  resumePrinting: function(e)
  {
    app.setPrinting();
    app.router.navigate("printing", {replace: true, trigger: true});
    app.router.printingView.togglePausePrint(e);

    this.$el.addClass('hide');
  },
  onPrintingProgressChanged: function(model, printingProgress)
  {
    var el = this.$('.back-to-print .filename');

    if (printingProgress && printingProgress.printFileName && printingProgress.printFileName != el.text()) {
      el.text(printingProgress.printFileName)
    }
  },
  onPausedChanged: function(model, paused)
  {
    if (paused) {
      this.listenTo(app.socketData, 'change:printing_progress', this.onPrintingProgressChanged);
      this.$el.addClass('print-paused');
    } else {
      this.stopListening(app.socketData, 'change:printing_progress');

      if (app.socketData.get('printing')) {
        app.router.navigate("printing", {replace: true, trigger: true});
      } else {
        this.$el.removeClass('print-paused');
      }
    }
  }
});
<|endoftext|>


<commit_before>'use strict'

$( document ).ready( function() {

	var quantity = 0,
		order = {};

	var seriesSets = [
		{
			name: 'Series 2',
			tag: 'series2',
			artists: [ 'beryl', 'sean', 'yulong', 'duofen', 'alessandro', 'yanzhen', 'garrett', 'zoe', 'jesse' ],
			artist_info: {
				beryl: {
					name: 'Beryl Chung',
					pieces: [
						{
							name: 'Blue Hawaii',
							tag: 'elvis'
						},
						{
							name: 'Mad Max: Furiosa',
							tag: 'furiosa'
						},
						{
							name: 'T.O.P. Doom Dada',
							tag: 'top'
						},
						{
							name: 'Kamikaze Girls',
							tag: 'kamikaze'
						},
						{
							name: 'Pulp Fiction',
							tag: 'pulp'
						},
					]
				},
				sean: {
					name: 'Sean Kiefer',
					pieces: [
						{
							name: 'Y\'all Know About Killin\'?',
							tag: 'platoon'
						},
						{
							name: 'Cause My Life is Dope, and I Do Dope Shit',
							tag: 'kanye'
						},
						{
							name: 'Make Like a Tree, and Get Outta Here',
							tag: 'bttf2'
						},
						{
							name: 'We Made You!',
							tag: 'maximum'
						},
						{
							name: 'I\'ll Swallow Your Soul',
							tag: 'evil_dead'
						}
					]
				},
				yulong: {
					name: 'Yulong Lli 李豫陇',
					pieces: [
						{
							name: 'Tom Dixon',
							tag: 'tomdixon'
						},
						{
							name: 'David Hockney',
							tag: 'davidhockney'
						},
						{
							name: 'Breakbot',
							tag: 'breakbot'
						},
						{
							name: 'Maison Kitsune',
							tag: 'maisonkitsune'
						},
						{
							name: 'Moonrise Kingdom',
							tag: 'moonrisekingdom'
						}
					]
				},
				duofen: {
					name: 'Duofen (Frieda) Ma',
					pieces: [
						{
							name: 'Wild Jungle',
							tag: 'gaga'
						},
						{
							name: 'The Force Dances',
							tag: 'starwars'
						},
						{
							name: 'Social Networking Addiction',
							tag: 'likes'
						},
						{
							name: 'Amusing Ourselves to Death',
							tag: 'amusing'
						},
						{
							name: 'Clockworking Orange',
							tag: 'clockworking'
						}
					]
				},
				alessandro: {
					name: 'Alessandro Echevarria',
					pieces: [
						{
							name: 'Hiroshi & Moto',
							tag: 'fujikofujio'
						},
						{
							name: 'Give, Open, Close, Pick up, Look at, Talk to, Use, Push, Pull',
							tag: 'lucasarts'
						},
						{
							name: 'Wednesday Night',
							tag: 'mattgroening'
						},
						{
							name: 'Woof.',
							tag: 'miyazaki'
						},
						{
							name: 'Bird Mountain',
							tag: 'toriyama'
						}
					]
				},
				yanzhen: {
					name: 'Li Yanzhen 李炎臻',
					pieces: [
						{
							name: '孙悟空',
							tag: 'dragonball'
						},
						{
							name: '机器猫',
							tag: 'doremon'
						},
						{
							name: '海绵宝宝',
							tag: 'spongebob'
						},
						{
							name: '皮卡丘',
							tag: 'pikachu'
						},
						{
							name: '超级玛丽',
							tag: 'mario'
						}
					]
				},
				garrett: {
					name: 'Garrett Mutz',
					pieces: [
						{
							name: 'Tarantino',
							tag: 'tarantino'
						},
						{
							name: 'El Barto',
							tag: 'bart'
						},
						{
							name: 'The Texas Rattlesnake',
							tag: 'stonecold'
						},
						{
							name: 'Master Jim',
							tag: 'jim'
						},
						{
							name: 'Boba',
							tag: 'boba'
						}
					]
				},
				zoe: {
					name: 'DARTHY',
					pieces: [
						{
							name: 'KAIJUS ATTACK',
							tag: 'kaiju'
						},
						{
							name: 'RASHIN RASHIN',
							tag: 'rashin'
						},
						{
							name: 'LEGS vs. LEGS',
							tag: 'legs'
						},
						{
							name: 'SKULL WARS',
							tag: 'skullwars'
						},
						{
							name: 'CROWS ZILLA',
							tag: 'crowszilla'
						}
					]
				},
				jesse: {
					name: 'Jesse Ryan',
					pieces: [
						{
							name: 'Jack Kirby',
							tag: 'orange'
						},
						{
							name: 'Stephen King',
							tag: 'red'
						},
						{
							name: 'Brian Wilson',
							tag: 'turquoise'
						},
						{
							name: 'Larry David',
							tag: 'yellow'
						},
						{
							name: 'John Carpenter',
							tag: 'blue'
						}
					]
				}

			}
		},
		{
			name: 'Series 1',
			tag: 'series1',
			artists: ['beryl', 'sean', 'darren', 'otto', 'patti'],
			artist_info: {
				beryl: {
					name: 'Beryl Chung',
					pieces: [
						{
							name: 'Bruce Lee',
							tag: 'bruce'
						},
						{
							name: 'Cassandra Cain',
							tag: 'batgirl'
						},
						{
							name: 'Pikachu',
							tag: 'pikachu'
						},
						{
							name: 'Wong Kar Wai',
							tag: 'wkw'
						},
						{
							name: 'High Fidelity',
							tag: 'hifi'
						},
					]
				},
				sean: {
					name: 'Sean Kiefer',
					pieces: [
						{
							name: 'Super Green',
							tag: 'fifth'
						},
						{
							name: 'Now, Plain Zero!',
							tag: 'action'
						},
						{
							name: 'Save the Clocktower',
							tag: 'bttf'
						},
						{
							name: 'ABACABB',
							tag: 'nes'
						},
						{
							name: 'The Velour Fog',
							tag: 'future'
						}
					]
				},
				darren: {
					name: 'Darren Crawforth',
					pieces: [
						{
							name: 'The Hand of Jonny Greenwood',
							tag: 'johnny'
						},
						{
							name: 'The Hips of Iggy Pop',
							tag: 'iggy'
						},
						{
							name: 'The Heart of Leonard Cohen',
							tag: 'leonard'
						},
						{
							name: 'The Brain of Kieran Hebden',
							tag: 'keiran'
						},
						{
							name: 'The Feet of Lee "Scratch" Perry',
							tag: 'scratch'
						},
					]
				},
				patti: {
					name: 'Patti Ruan',
					pieces: [
						{
							name: 'All About My Mother',
							tag: 'mother'
						},
						{
							name: 'Live with Spongebob',
							tag: 'spongebob'
						},
						{
							name: 'Bath with DragonBall',
							tag: 'bath'
						},
						{
							name: 'Always Love the Doors',
							tag: 'doors'
						},
						{
							name: 'Everyone is HAL9000',
							tag: 'hal'
						},

					]
				},
				otto: {
					name: 'Otto Som',
					pieces: [
						{
							name: 'BIG LOVE',
							tag: 'love'
						},
						{
							name: 'DREAM OF SODOM',
							tag: 'sodom'
						},
						{
							name: 'TALK TO MY PUSSY',
							tag: 'pussy'
						},
						{
							name: 'THE HEAVENLY STAREAII',
							tag: 'heaven'
						},
						{
							name: 'ALL SHE HAS LEFT',
							tag: 'gold'
						},
					]
				}
			}
		}
	];

	emailjs.init("user_17IFxUh62EclEap0rJrrN");

	// EVENTUALLY ADD SEPERATE PAGE FOR SERIES 1 PURCHASES
	// TODO: DISABLE OTTO POSTERS FROM STORE

	var series = seriesSets[0];

	series.artists.forEach( function( key ) {
		var artist = series.artist_info[ key ];
		var pieces = artist.pieces;

		var store = $( '

' );

		$( store ).append( "
" + artist.name+"
" );

		var previews = $( '

' ).addClass( 'store-wrapper clearfix' );
		pieces.forEach( function( piece ) {
			var itemEl = "

" + piece.name + "
<input type='number'>
";
			$( previews ).append( itemEl );
		});

		$( store ).append( previews );
		$( '#stores' ).append( store );
	});

	$( '#stores' ).append( '<button class="submit-btn" id="submitChoices">Check Out</button>' );

	$('#submitQuantity').click( function( event ) {
		console.log('click');
		console.log('here');
		quantity = document.getElementById('quantityInput').value;
		if ( quantity > 0 ) {
			$('.quantity-shade').removeClass('show');
			$('#stores').addClass('show');
			$('#quantityInput').val("");
			console.log('here');
		}
	});

	var selectedQuantity;
	$('.store-item img').click( function( event ) {
		selectedQuantity = 0;
		var parent = $(this).parent();
		$('.store-item.selected input').each(function() {
			selectedQuantity += parseInt( $(this).val() );
		});
		if( parent.hasClass('selected') ) {
			parent.removeClass('selected');
			selectedQuantity -= parseInt(parent.children('input').val());
			parent.children('input').val(0);
		} else if ( selectedQuantity < quantity ) {
			parent.addClass('selected');
			parent.children('input').val(1);
			selectedQuantity += 1
			if ( selectedQuantity == quantity ) {
				$('#submitChoices').addClass('active');
			}
		}
	});

	$('#submitChoices').click(function(){
		if( !$(this).hasClass('active') ) return;

		selectedQuantity = 0;
		$('.store-item.selected input').each(function(){
			selectedQuantity += parseInt($(this).val());
		});

		if( selectedQuantity > quantity ) {
			alert('Too many posters selected');
			return;
		}

		order.items = [];
		$('.store-item.selected').each(function(){
			order.items.push({
				artist: $(this).data('name'),
				title: $(this).data('piece'),
				quantity: parseInt($(this).children('input').val())
			});
		});

		$('.info-wrapper').addClass('show');
		window.scrollTo( 0, 0 );
		$('.customer-info').addClass('display');
		$('.store').removeClass('show');
	});

	$('#backButton').click( function() {
		$('.store').addClass('show');
		$('.info-wrapper').removeClass('show');
		$('.custom-info').removeClass('display');
		$('#stores').scrollTop(0);
	});

	$('#submitOrder').click( function() {
		// check required fields
		var flag = false;

		$('.required').each(function(){
			if( !$(this).val() ) {
				$(this).addClass('has-error');
				flag = true;
			}
		});

		if (flag) return;

		order.contact = {
			name: $('#contactName').val(),
			email: $('#contactEmail').val(),
			address: $('#contactAddress').val(),
			wechat: $('#contactWechat').val(),
			phone: $('#contactPhone').val()
		};

		console.log(order);

		var loaderEl = '

';
		$('#submitOrder').html(loaderEl);

		emailjs.send("outlook", "top5_order", order)
			.then(function(response) {
				console.log("SUCCESS. status=%d, text=%s", response.status, response.text);
				$('.customer-info').removeClass('display');
				window.scrollTo(0,0);
				$('.success-message').addClass('display');
				$('#submitOrder').html("Submit");
				// reset form values
				$('#contactName').val("");
				$('#contactEmail').val("");
				$('#contactAddress').val("");
				$('#contactWechat').val("");
				$('#contactPhone').val("");
			}, function(err) {
				console.log("FAILED. error=", err);
				$('#submitOrder').html("Submit");
				alert('Order Failed: check connection and try again');
			});
	});

	$('#submitReset').click(function(){
		quantity = 0;
		order = {};
		$('#stores').scrollTop(0);
		$('.store-item').removeClass('selected');
		$('.store-item').children('input').val(0);
		$('.success-message').removeClass('display');
		$('.quantity-shade').addClass('show');
		$('.info-wrapper').removeClass('show');
	});

});

<commit_msg>WIP: Adding support for localStorage stashing incase send fails more than twice. - Need to add paring of local storage to try to send previously saved orders<commit_after>'use strict'

$( document ).ready( function() {

	var quantity = 0,
		order = {};

	var seriesSets = [
		{
			name: 'Series 2',
			tag: 'series2',
			artists: [ 'beryl', 'sean', 'yulong', 'duofen', 'alessandro', 'yanzhen', 'garrett', 'zoe', 'jesse' ],
			artist_info: {
				beryl: {
					name: 'Beryl Chung',
					pieces: [
						{
							name: 'Blue Hawaii',
							tag: 'elvis'
						},
						{
							name: 'Mad Max: Furiosa',
							tag: 'furiosa'
						},
						{
							name: 'T.O.P. Doom Dada',
							tag: 'top'
						},
						{
							name: 'Kamikaze Girls',
							tag: 'kamikaze'
						},
						{
							name: 'Pulp Fiction',
							tag: 'pulp'
						},
					]
				},
				sean: {
					name: 'Sean Kiefer',
					pieces: [
						{
							name: 'Y\'all Know About Killin\'?',
							tag: 'platoon'
						},
						{
							name: 'Cause My Life is Dope, and I Do Dope Shit',
							tag: 'kanye'
						},
						{
							name: 'Make Like a Tree, and Get Outta Here',
							tag: 'bttf2'
						},
						{
							name: 'We Made You!',
							tag: 'maximum'
						},
						{
							name: 'I\'ll Swallow Your Soul',
							tag: 'evil_dead'
						}
					]
				},
				yulong: {
					name: 'Yulong Lli 李豫陇',
					pieces: [
						{
							name: 'Tom Dixon',
							tag: 'tomdixon'
						},
						{
							name: 'David Hockney',
							tag: 'davidhockney'
						},
						{
							name: 'Breakbot',
							tag: 'breakbot'
						},
						{
							name: 'Maison Kitsune',
							tag: 'maisonkitsune'
						},
						{
							name: 'Moonrise Kingdom',
							tag: 'moonrisekingdom'
						}
					]
				},
				duofen: {
					name: 'Duofen (Frieda) Ma',
					pieces: [
						{
							name: 'Wild Jungle',
							tag: 'gaga'
						},
						{
							name: 'The Force Dances',
							tag: 'starwars'
						},
						{
							name: 'Social Networking Addiction',
							tag: 'likes'
						},
						{
							name: 'Amusing Ourselves to Death',
							tag: 'amusing'
						},
						{
							name: 'Clockworking Orange',
							tag: 'clockworking'
						}
					]
				},
				alessandro: {
					name: 'Alessandro Echevarria',
					pieces: [
						{
							name: 'Hiroshi & Moto',
							tag: 'fujikofujio'
						},
						{
							name: 'Give, Open, Close, Pick up, Look at, Talk to, Use, Push, Pull',
							tag: 'lucasarts'
						},
						{
							name: 'Wednesday Night',
							tag: 'mattgroening'
						},
						{
							name: 'Woof.',
							tag: 'miyazaki'
						},
						{
							name: 'Bird Mountain',
							tag: 'toriyama'
						}
					]
				},
				yanzhen: {
					name: 'Li Yanzhen 李炎臻',
					pieces: [
						{
							name: '孙悟空',
							tag: 'dragonball'
						},
						{
							name: '机器猫',
							tag: 'doremon'
						},
						{
							name: '海绵宝宝',
							tag: 'spongebob'
						},
						{
							name: '皮卡丘',
							tag: 'pikachu'
						},
						{
							name: '超级玛丽',
							tag: 'mario'
						}
					]
				},
				garrett: {
					name: 'Garrett Mutz',
					pieces: [
						{
							name: 'Tarantino',
							tag: 'tarantino'
						},
						{
							name: 'El Barto',
							tag: 'bart'
						},
						{
							name: 'The Texas Rattlesnake',
							tag: 'stonecold'
						},
						{
							name: 'Master Jim',
							tag: 'jim'
						},
						{
							name: 'Boba',
							tag: 'boba'
						}
					]
				},
				zoe: {
					name: 'DARTHY',
					pieces: [
						{
							name: 'KAIJUS ATTACK',
							tag: 'kaiju'
						},
						{
							name: 'RASHIN RASHIN',
							tag: 'rashin'
						},
						{
							name: 'LEGS vs. LEGS',
							tag: 'legs'
						},
						{
							name: 'SKULL WARS',
							tag: 'skullwars'
						},
						{
							name: 'CROWS ZILLA',
							tag: 'crowszilla'
						}
					]
				},
				jesse: {
					name: 'Jesse Ryan',
					pieces: [
						{
							name: 'Jack Kirby',
							tag: 'orange'
						},
						{
							name: 'Stephen King',
							tag: 'red'
						},
						{
							name: 'Brian Wilson',
							tag: 'turquoise'
						},
						{
							name: 'Larry David',
							tag: 'yellow'
						},
						{
							name: 'John Carpenter',
							tag: 'blue'
						}
					]
				}

			}
		},
		{
			name: 'Series 1',
			tag: 'series1',
			artists: ['beryl', 'sean', 'darren', 'otto', 'patti'],
			artist_info: {
				beryl: {
					name: 'Beryl Chung',
					pieces: [
						{
							name: 'Bruce Lee',
							tag: 'bruce'
						},
						{
							name: 'Cassandra Cain',
							tag: 'batgirl'
						},
						{
							name: 'Pikachu',
							tag: 'pikachu'
						},
						{
							name: 'Wong Kar Wai',
							tag: 'wkw'
						},
						{
							name: 'High Fidelity',
							tag: 'hifi'
						},
					]
				},
				sean: {
					name: 'Sean Kiefer',
					pieces: [
						{
							name: 'Super Green',
							tag: 'fifth'
						},
						{
							name: 'Now, Plain Zero!',
							tag: 'action'
						},
						{
							name: 'Save the Clocktower',
							tag: 'bttf'
						},
						{
							name: 'ABACABB',
							tag: 'nes'
						},
						{
							name: 'The Velour Fog',
							tag: 'future'
						}
					]
				},
				darren: {
					name: 'Darren Crawforth',
					pieces: [
						{
							name: 'The Hand of Jonny Greenwood',
							tag: 'johnny'
						},
						{
							name: 'The Hips of Iggy Pop',
							tag: 'iggy'
						},
						{
							name: 'The Heart of Leonard Cohen',
							tag: 'leonard'
						},
						{
							name: 'The Brain of Kieran Hebden',
							tag: 'keiran'
						},
						{
							name: 'The Feet of Lee "Scratch" Perry',
							tag: 'scratch'
						},
					]
				},
				patti: {
					name: 'Patti Ruan',
					pieces: [
						{
							name: 'All About My Mother',
							tag: 'mother'
						},
						{
							name: 'Live with Spongebob',
							tag: 'spongebob'
						},
						{
							name: 'Bath with DragonBall',
							tag: 'bath'
						},
						{
							name: 'Always Love the Doors',
							tag: 'doors'
						},
						{
							name: 'Everyone is HAL9000',
							tag: 'hal'
						},

					]
				},
				otto: {
					name: 'Otto Som',
					pieces: [
						{
							name: 'BIG LOVE',
							tag: 'love'
						},
						{
							name: 'DREAM OF SODOM',
							tag: 'sodom'
						},
						{
							name: 'TALK TO MY PUSSY',
							tag: 'pussy'
						},
						{
							name: 'THE HEAVENLY STAREAII',
							tag: 'heaven'
						},
						{
							name: 'ALL SHE HAS LEFT',
							tag: 'gold'
						},
					]
				}
			}
		}
	];

	emailjs.init("user_17IFxUh62EclEap0rJrrN");

	// EVENTUALLY ADD SEPERATE PAGE FOR SERIES 1 PURCHASES
	// TODO: DISABLE OTTO POSTERS FROM STORE

	var series = seriesSets[0];

	series.artists.forEach( function( key ) {
		var artist = series.artist_info[ key ];
		var pieces = artist.pieces;

		var store = $( '

' );

		$( store ).append( "
" + artist.name+"
" );

		var previews = $( '

' ).addClass( 'store-wrapper clearfix' );
		pieces.forEach( function( piece ) {
			var itemEl = "

" + piece.name + "
<input type='number'>
";
			$( previews ).append( itemEl );
		});

		$( store ).append( previews );
		$( '#stores' ).append( store );
	});

	$( '#stores' ).append( '<button class="submit-btn" id="submitChoices">Check Out</button>' );

	$('#submitQuantity').click( function( event ) {
		console.log('click');
		console.log('here');
		quantity = document.getElementById('quantityInput').value;
		if ( quantity > 0 ) {
			$('.quantity-shade').removeClass('show');
			$('#stores').addClass('show');
			$('#quantityInput').val("");
			console.log('here');
		}
	});

	var selectedQuantity;
	$('.store-item img').click( function( event ) {
		selectedQuantity = 0;
		var parent = $(this).parent();
		$('.store-item.selected input').each(function() {
			selectedQuantity += parseInt( $(this).val() );
		});
		if( parent.hasClass('selected') ) {
			parent.removeClass('selected');
			selectedQuantity -= parseInt(parent.children('input').val());
			parent.children('input').val(0);
		} else if ( selectedQuantity < quantity ) {
			parent.addClass('selected');
			parent.children('input').val(1);
			selectedQuantity += 1
			if ( selectedQuantity == quantity ) {
				$('#submitChoices').addClass('active');
			}
		}
	});

	$( '#submitChoices' ).click( function() {
		if( !$(this).hasClass('active') ) return;

		selectedQuantity = 0;
		$('.store-item.selected input').each(function(){
			selectedQuantity += parseInt($(this).val());
		});

		if( selectedQuantity > quantity ) {
			alert('Too many posters selected');
			return;
		}

		order.items = [];
		$('.store-item.selected').each(function(){
			order.items.push({
				artist: $(this).data('name'),
				title: $(this).data('piece'),
				quantity: parseInt($(this).children('input').val())
			});
		});

		$('.info-wrapper').addClass('show');
		window.scrollTo( 0, 0 );
		$('.customer-info').addClass('display');
		$('.store').removeClass('show');
	});

	$('#backButton').click( function() {
		$('.store').addClass('show');
		$('.info-wrapper').removeClass('show');
		$('.custom-info').removeClass('display');
		$('#stores').scrollTop(0);
	});

	var submitting = false;
	$( '#submitOrder' ).click( function() {
		if ( submitting ) return;
		submitting = true;
		var submitTries = 0;

		// check required fields
		var flag = false;
		$('.required').each(function(){
			if( !$(this).val() ) {
				$(this).addClass('has-error');
				flag = true;
			}
		});
		if ( flag ) {
			submitting = false;
			return;
		}

		order.contact = {
			name: $('#contactName').val(),
			email: $('#contactEmail').val(),
			address: $('#contactAddress').val(),
			wechat: $('#contactWechat').val(),
			phone: $('#contactPhone').val()
		};

		console.log(order);

		var loaderEl = '

';
		$('#submitOrder').html(loaderEl);

		var sendEmail = function() {
			console.log( 'Sending Email: Try ' + submitTries );

			var completeOrder = function(response) {
				if ( response ) {
					console.log("SUCCESS. status=%d, text=%s", response.status, response.text );
				}
				$('.customer-info').removeClass('display');
				window.scrollTo(0,0);
				$('.success-message').addClass('display');
				$('#submitOrder').html("Submit");
				// reset form values
				$('#contactName').val("");
				$('#contactEmail').val("");
				$('#contactAddress').val("");
				$('#contactWechat').val("");
				$('#contactPhone').val("");

				// reset order object
				order = {};
				quantity = 0;

				submitting = false;
			};

			var stashOrder = function() {
				var orders = [];
				orders.push( order );
				localStorage.t5_stashedOrders = JSON.stringify( orders );
				completeOrder({ text: 'Order saved in Local Storage' });
				console.log( localStorage );
			};

			emailjs.send( "outlook", "top5_order", order )
				.then(
					function( response ) {
						completeOrder(response);
					},
					function(err) {
						console.log("FAILED. error=", err);
						submitTries++;
						if ( submitTries < 2 ) {
							sendEmail();
						} else {
							stashOrder();
						}
					}
				);
		};

		sendEmail();
	});

	$('#submitReset').click(function(){
		quantity = 0;
		order = {};
		$('#stores').scrollTop(0);
		$('.store-item').removeClass('selected');
		$('.store-item').children('input').val(0);
		$('.success-message').removeClass('display');
		$('.quantity-shade').addClass('show');
		$('.info-wrapper').removeClass('show');
	});

});

<|endoftext|>


<commit_before>/*
Copyright 2011 Museum of Moving Image

Licensed under the Educational Community License (ECL), Version 2.0.
You may not use this file except in compliance with this License.

You may obtain a copy of the ECL 2.0 License at
https://source.collectionspace.org/collection-space/LICENSE.txt
*/

/*global cspace:true, jQuery, fluid, window*/
"use strict";

cspace = cspace || {};

(function ($, fluid) {

    fluid.defaults("cspace.advancedSearch", {
        gradeNames: ["autoInit", "fluid.rendererComponent"],
        produceTree: "cspace.advancedSearch.produceTree",
        components: {
            recordTypeSelector: {
                type: "cspace.util.recordTypeSelector",
                options: {
                    related: ["cataloging", "procedures", "vocabularies"],
                    dom: "{advancedSearch}.dom",
                    componentID: "recordTypeSelect",
                    selector: "recordTypeSelect",
                    permission: "{advancedSearch}.options.permission"
                }
            },
            fetcher: {
                type: "cspace.advancedSearch.fetcher",
                options: {
                    events: {
                        fetchOn: "{advancedSearch}.events.recordTypeChanged",
                        afterFetch: "{advancedSearch}.events.afterFetch"
                    }
                },
                priority: "first"
            },
            searchHistoryStorage: {
                type: "cspace.util.localStorageDataSource",
                options: {
                    elPath: "searchHistory"
                }
            }
        },
        events: {
            recordTypeChanged: null,
            afterFetch: null,
            afterSearchFieldsInit: null,
            onSearch: null,
            afterSearch: null,
            afterToggle: null
        },
        model: {
            andOrList: ["or", "and"],
            andOrNames: {
                expander: {
                    type: "fluid.deferredInvokeCall",
                    func: "cspace.advancedSearch.buildAndOrNames",
                    args: "{globalBundle}.messageBase"
                }
            },
            operation: "or",
            keywords: ""
        },
        permission: "list",
        selectors: {
            toggle: ".csc-advancedSearch-toggle",
            advancedSearch: ".csc-advancedSearch-template",
            step1: ".csc-advancedSearch-step1",
            step1Header: ".csc-advancedSearch-step1-header",
            step1Label: ".csc-advancedSearch-step1-label",
            step1Name: ".csc-advancedSearch-step1-name",
            recordTypeSelect: ".csc-advancedSearch-selectRecordType",
            step2: ".csc-advancedSearch-step2",
            step2Header: ".csc-advancedSearch-step2-header",
            step2Label: ".csc-advancedSearch-step2-label",
            step2Name: ".csc-advancedSearch-step2-name",
            query: ".csc-advancedSearch-query",
            searchButton: ".csc-advancedSearch-searchButton",
            step2SubHeader1: ".csc-advancedSearch-step2-subheader1",
            step2SubHeader1Label : ".csc-advancedSearch-step2-subheader1-label",
            step2SubHeader1Note : ".csc-advancedSearch-step2-subheader1-note",
            step2SubHeader2: ".csc-advancedSearch-step2-subheader2",
            step2SubHeader2Label : ".csc-advancedSearch-step2-subheader2-label",
            step2SubHeader2Note1 : ".csc-advancedSearch-step2-subheader2-note1",
            step2SubHeader2AndOr : ".csc-advancedSearch-step2-subheader2-andOr",
            step2SubHeader2Note2 : ".csc-advancedSearch-step2-subheader2-note2",
            searchFields : ".csc-advancedSearch-searchFields"
        },
        styles: {
            toggle: "cs-advancedSearch-toggle",
            advancedSearch: "cs-advancedSearch-template",
            step1: "cs-advancedSearch-step1",
            step1Header: "cs-advancedSearch-step1-header",
            step1Label: "cs-advancedSearch-step1-label",
            step1Name: "cs-advancedSearch-step1-name",
            recordTypeSelect: "cs-advancedSearch-selectRecordType",
            step2: "cs-advancedSearch-step2",
            step2Header: "cs-advancedSearch-step2-header",
            step2Label: "cs-advancedSearch-step2-label",
            step2Name: "cs-advancedSearch-step2-name",
            query: "cs-advancedSearch-query",
            searchButton: "cs-advancedSearch-searchButton",
            step2SubHeader1: "cs-advancedSearch-step2-subheader1",
            step2SubHeader1Label : "cs-advancedSearch-step2-subheader1-label",
            step2SubHeader1Note : "cs-advancedSearch-step2-subheader1-note",
            step2SubHeader2: "cs-advancedSearch-step2-subheader2",
            step2SubHeader2Label : "cs-advancedSearch-step2-subheader2-label",
            step2SubHeader2Note1 : "cs-advancedSearch-step2-subheader2-note1",
            step2SubHeader2AndOr : "cs-advancedSearch-step2-subheader2-andOr",
            step2SubHeader2Note2 : "cs-advancedSearch-step2-subheader2-note2",
            searchFields : "cs-advancedSearch-searchFields"
        },
        resources: {
            template: cspace.resourceSpecExpander({
                fetchClass: "fastTemplate",
                url: "%webapp/html/components/AdvancedSearchTemplate.html",
                options: {
                    dataType: "html"
                }
            })
        },
        invokers: {
            initSearchFields: {
                funcName: "cspace.advancedSearch.initSearchFields",
                args: ["{advancedSearch}", "{instantiator}", "{arguments}.0"]
            },
            search: {
                funcName: "cspace.advancedSearch.search",
                args: ["{advancedSearch}.events.onSearch", "{advancedSearch}.model", "{searchFields}.model"]
            },
            toggle: {
                funcName: "cspace.advancedSearch.toggle",
                args: ["{advancedSearch}.toggleControls", "{advancedSearch}.events.afterToggle"]
            },
            updateSearchHistory: "cspace.advancedSearch.updateSearchHistory"
        },
        strings: {},
        parentBundle: "{globalBundle}",
        finalInitFunction: "cspace.advancedSearch.finalInit",
        postInitFunction: "cspace.advancedSearch.postInit",
        preInitFunction: "cspace.advancedSearch.preInit"
    });

    cspace.advancedSearch.toggle = function (toggleControls, event) {
        toggleControls(false);
        event.fire();
    };

    var transformSearchModel = function (keywordModel, rules) {
        return fluid.model.transformWithRules(fluid.copy(keywordModel), rules);
    };

    cspace.advancedSearch.search = function (searchEvent, keywordModel, fieldsModel) {
        var searchModel = {};
        var rules = {
            "recordType": "recordType",
            "keywords": "keywords"
        };
        if (fieldsModel) {
            rules.operation = "operation";
            searchModel.fields = fluid.copy(fieldsModel);
        }
        fluid.merge(null, searchModel, transformSearchModel(keywordModel, rules));
        searchEvent.fire(searchModel)
    };

    cspace.advancedSearch.initSearchFields = function (that, instantiator, options) {
        if (that.searchFields) {
            instantiator.clearComponent(that, ["searchFields"]);
        }
        that.options.searchFields = that.options.searchFields || {};
        var defaultModel = fluid.copy(that.options.defaultFieldsModel);
        delete that.options.defaultFieldsModel;
        var model = defaultModel || cspace.util.getBeanValue({}, options.recordType, options.uischema);
        var applier = fluid.makeChangeApplier(model, {thin: true});
        that.options.searchFields = {
            model: model,
            applier: applier,
            schema: options.uischema
        };
        that.options.components.searchFields = {
            type: "cspace.advancedSearch.searchFields",
            container: "{advancedSearch}.dom.searchFields",
            options: {
                uispec: options.uispec,
                applier: "{advancedSearch}.options.searchFields.applier",
                model: "{advancedSearch}.options.searchFields.model",
                recordType: options.recordType,
                resources: {
                    template: options.template
                }
            }
        };
        fluid.initDependent(that, "searchFields", instantiator);
        that.events.afterSearchFieldsInit.fire();
    };

    cspace.advancedSearch.preInit = function (that) {
        cspace.util.preInitMergeListeners(that.options, {
            afterFetch: function (options) {
                that.initSearchFields(options);
            },
            recordTypeChanged: function () {
                that.locate("searchFields").hide();
            },
            afterSearchFieldsInit: function () {
                that.locate("searchFields").show();
            },
            onSearch: function (searchModel) {
                that.toggleControls(true);
            },
            afterSearch: function (searchModel) {
                that.updateSearchHistory(searchModel);
            }
        });
    };

    cspace.advancedSearch.postInit = function (that) {
        that.applier.modelChanged.addListener("recordType", function () {
            that.events.recordTypeChanged.fire(that.model.recordType);
        });
    };

    cspace.advancedSearch.finalInit = function (that) {
        that.toggleControls = function (hideSteps) {
            that.locate("step1").add(that.locate("step2"))[hideSteps ? "hide" : "show"]();
            that.locate("toggle")[hideSteps ? "show" : "hide"]();
        };
        that.refreshView();
    };

    cspace.advancedSearch.produceTree = function (that) {
        var tree = {
            advancedSearch: {decorators: {"addClass": "{styles}.advancedSearch"}},
            step2SubHeader1: {decorators: {"addClass": "{styles}.step2SubHeader1"}},
            step2SubHeader2: {decorators: {"addClass": "{styles}.step2SubHeader2"}},
            step1: {decorators: {"addClass": "{styles}.step1"}},
            step1Header: {decorators: {"addClass": "{styles}.step1Header"}},
            step1Label: {
                decorators: {"addClass": "{styles}.step1Label"},
                messagekey: "advancedSearch-step1Label"
            },
            step1Name: {
                decorators: {"addClass": "{styles}.step1Name"},
                messagekey: "advancedSearch-step1Name"
            },
            step2: {decorators: {"addClass": "{styles}.step2"}},
            step2Header: {decorators: {"addClass": "{styles}.step2Header"}},
            step2Label: {
                decorators: {"addClass": "{styles}.step2Label"},
                messagekey: "advancedSearch-step2Label"
            },
            step2Name: {
                decorators: {"addClass": "{styles}.step2Name"},
                messagekey: "advancedSearch-step2Name"
            },
            step2SubHeader1Label: {
                decorators: {"addClass": "{styles}.step2SubHeader1Label"},
                messagekey: "advancedSearch-step2SubHeader1Label"
            },
            step2SubHeader1Note: {
                decorators: {"addClass": "{styles}.step2SubHeader1Note"},
                messagekey: "advancedSearch-step2SubHeader1Note"
            },
            step2SubHeader2Label: {
                decorators: {"addClass": "{styles}.step2SubHeader2Label"},
                messagekey: "advancedSearch-step2SubHeader2Label"
            },
            step2SubHeader2Note1: {
                decorators: {"addClass": "{styles}.step2SubHeader2Note1"},
                messagekey: "advancedSearch-step2SubHeader2Note1"
            },
            step2SubHeader2Note2: {
                decorators: {"addClass": "{styles}.step2SubHeader2Note2"},
                messagekey: "advancedSearch-step2SubHeader2Note2"
            },
            step2SubHeader2AndOr: {
                optionnames: "${andOrNames}",
                optionlist: "${andOrList}",
                selection: "${operation}",
                decorators: {"addClass": "{styles}.step2SubHeader2AndOr"}
            },
            query: {
                value: "${keywords}",
                decorators: {"addClass": "{styles}.query"}
            },
            searchButton: {
                decorators: [{
                    type: "attrs",
                    attributes: {
                        value: that.options.parentBundle.messageBase["advancedSearch-searchButton"]
                    }
                }, {
                    type: "jQuery",
                    func: "click",
                    args: that.search
                }, {
                    addClass: "{styles}.searchButton"
                }]
            },
            toggle: {
                decorators: [{
                    type: "attrs",
                    attributes: {
                        value: that.options.parentBundle.messageBase["advancedSearch-toggle"]
                    }
                }, {
                    type: "jQuery",
                    func: "click",
                    args: that.toggle
                }, {
                    addClass: "{styles}.toggle"
                }]
            },
            searchFields: {decorators: {addClass: "{styles}.searchFields"}}
        };
        tree = $.extend(tree, that.recordTypeSelector.produceComponent());
        // TODO: This is a hack, recordTypeSelector's selection can't be bound.
        if (!that.model.recordType) {
            that.applier.requestChange("recordType", tree.recordTypeSelect.selection);
        }
        tree.recordTypeSelect.selection = "${recordType}";
        tree.recordTypeSelect.decorators = {"addClass": "{styles}.recordTypeSelect"};
        return tree;
    };

    fluid.fetchResources.primeCacheFromResources("cspace.advancedSearch");

    cspace.advancedSearch.buildAndOrNames = function (messageBase) {
        return fluid.transform(["or", "and"], function (value) {
            return messageBase["advancedSearch-" + value];
        });
    };

    fluid.defaults("cspace.advancedSearch.searchFields", {
        gradeNames: ["autoInit", "fluid.rendererComponent"],
        produceTree: "cspace.advancedSearch.searchFields.produceTree",
        mergePolicy: {
            model: "preserve",
            applier: "nomerge",
            "rendererOptions.instantiator": "nomerge",
            "rendererOptions.parentComponent": "nomerge",
            "rendererFnOptions.uispec": "uispec",
            "rendererOptions.applier": "applier",
            uispec: "noexpand",
            schema: "nomerge"
        },
        renderOnInit: true,
        rendererFnOptions: {
            cutpointGenerator: "cspace.advancedSearch.searchFields.cutPointGenerator"
        },
        rendererOptions: {
            instantiator: "{instantiator}",
            parentComponent: "{searchFields}"
        },
        strings: {},
        parentBundle: "{globalBundle}"
    });

    cspace.advancedSearch.searchFields.produceTree = function (that) {
        return that.options.uispec;
    };

    cspace.advancedSearch.searchFields.cutPointGenerator = function (selectors, options) {
        return cspace.renderUtils.cutpointsFromUISpec(options.uispec);
    };

    fluid.defaults("cspace.advancedSearch.fetcher", {
        gradeNames: ["autoInit", "fluid.eventedComponent"],
        preInitFunction: "cspace.advancedSearch.fetcher.preInit",
        resourceSpec: {
            template: {
                href: cspace.componentUrlBuilder("%webapp/html/components/SearchFieldsTemplate-%recordType.html"),
                options: {
                    dataType: "html",
                    forceCache: true
                }
            },
            uispec: {
                href: cspace.componentUrlBuilder("%tenant/%tname/%recordType-search/uispec"),
                options: {
                    dataType: "json",
                    forceCache: true
                }
            },
            uischema: {
                href: cspace.componentUrlBuilder("%tenant/%tname/%recordType-search/uischema"),
                options: {
                    dataType: "json",
                    forceCache: true
                }
            }
        },
        events: {
            afterFetch: null
        },
        invokers: {
            displayErrorMessage: "cspace.util.displayErrorMessage",
            lookupMessage: "cspace.util.lookupMessage"
        }
    });

    cspace.advancedSearch.fetcher.preInit = function (that) {
        that.fetch = function (recordType) {
            var resourceSpec = fluid.copy(that.options.resourceSpec);
            fluid.each(resourceSpec, function (spec) {
                spec.href = fluid.stringTemplate(spec.href, {recordType: recordType});
                spec.options.error = cspace.util.provideErrorCallback(that, spec.href, "errorFetching");
                spec.options.success = function (data) {
                    if (!data) {
                        that.displayErrorMessage(fluid.stringTemplate(that.lookupMessage("emptyResponse"), {
                            url: spec.href
                        }));
                        return;
                    }
                    if (data.isError === true) {
                        fluid.each(data.messages, function (message) {
                            that.displayErrorMessage(message);
                        });
                        return;
                    }
                };
            });
            fluid.fetchResources(resourceSpec, function () {
                that.events.afterFetch.fire({
                    template: resourceSpec.template,
                    uispec: resourceSpec.uispec.resourceText,
                    uischema: resourceSpec.uischema.resourceText,
                    recordType: recordType
                });
            });
        };

        that.options.listeners = {
            fetchOn: that.fetch
        };
    };

})(jQuery, fluid);<commit_msg>#CSPACE-3308: Fixed issue with disabling divider in advanced searcg<commit_after>/*
Copyright 2011 Museum of Moving Image

Licensed under the Educational Community License (ECL), Version 2.0.
You may not use this file except in compliance with this License.

You may obtain a copy of the ECL 2.0 License at
https://source.collectionspace.org/collection-space/LICENSE.txt
*/

/*global cspace:true, jQuery, fluid, window*/
"use strict";

cspace = cspace || {};

(function ($, fluid) {

    fluid.defaults("cspace.advancedSearch", {
        gradeNames: ["autoInit", "fluid.rendererComponent"],
        produceTree: "cspace.advancedSearch.produceTree",
        components: {
            recordTypeSelector: {
                type: "cspace.util.recordTypeSelector",
                options: {
                    related: ["cataloging", "procedures", "vocabularies"],
                    dom: "{advancedSearch}.dom",
                    componentID: "recordTypeSelect",
                    selector: "recordTypeSelect",
                    permission: "{advancedSearch}.options.permission"
                }
            },
            fetcher: {
                type: "cspace.advancedSearch.fetcher",
                options: {
                    events: {
                        fetchOn: "{advancedSearch}.events.recordTypeChanged",
                        afterFetch: "{advancedSearch}.events.afterFetch"
                    }
                },
                priority: "first"
            },
            searchHistoryStorage: {
                type: "cspace.util.localStorageDataSource",
                options: {
                    elPath: "searchHistory"
                }
            }
        },
        events: {
            recordTypeChanged: null,
            afterFetch: null,
            afterSearchFieldsInit: null,
            onSearch: null,
            afterSearch: null,
            afterToggle: null
        },
        model: {
            andOrList: ["or", "and"],
            andOrNames: {
                expander: {
                    type: "fluid.deferredInvokeCall",
                    func: "cspace.advancedSearch.buildAndOrNames",
                    args: "{globalBundle}.messageBase"
                }
            },
            operation: "or",
            keywords: ""
        },
        permission: "list",
        selectors: {
            toggle: ".csc-advancedSearch-toggle",
            advancedSearch: ".csc-advancedSearch-template",
            step1: ".csc-advancedSearch-step1",
            step1Header: ".csc-advancedSearch-step1-header",
            step1Label: ".csc-advancedSearch-step1-label",
            step1Name: ".csc-advancedSearch-step1-name",
            recordTypeSelect: ".csc-advancedSearch-selectRecordType",
            step2: ".csc-advancedSearch-step2",
            step2Header: ".csc-advancedSearch-step2-header",
            step2Label: ".csc-advancedSearch-step2-label",
            step2Name: ".csc-advancedSearch-step2-name",
            query: ".csc-advancedSearch-query",
            searchButton: ".csc-advancedSearch-searchButton",
            step2SubHeader1: ".csc-advancedSearch-step2-subheader1",
            step2SubHeader1Label : ".csc-advancedSearch-step2-subheader1-label",
            step2SubHeader1Note : ".csc-advancedSearch-step2-subheader1-note",
            step2SubHeader2: ".csc-advancedSearch-step2-subheader2",
            step2SubHeader2Label : ".csc-advancedSearch-step2-subheader2-label",
            step2SubHeader2Note1 : ".csc-advancedSearch-step2-subheader2-note1",
            step2SubHeader2AndOr : ".csc-advancedSearch-step2-subheader2-andOr",
            step2SubHeader2Note2 : ".csc-advancedSearch-step2-subheader2-note2",
            searchFields : ".csc-advancedSearch-searchFields"
        },
        styles: {
            toggle: "cs-advancedSearch-toggle",
            advancedSearch: "cs-advancedSearch-template",
            step1: "cs-advancedSearch-step1",
            step1Header: "cs-advancedSearch-step1-header",
            step1Label: "cs-advancedSearch-step1-label",
            step1Name: "cs-advancedSearch-step1-name",
            recordTypeSelect: "cs-advancedSearch-selectRecordType",
            step2: "cs-advancedSearch-step2",
            step2Header: "cs-advancedSearch-step2-header",
            step2Label: "cs-advancedSearch-step2-label",
            step2Name: "cs-advancedSearch-step2-name",
            query: "cs-advancedSearch-query",
            searchButton: "cs-advancedSearch-searchButton",
            step2SubHeader1: "cs-advancedSearch-step2-subheader1",
            step2SubHeader1Label : "cs-advancedSearch-step2-subheader1-label",
            step2SubHeader1Note : "cs-advancedSearch-step2-subheader1-note",
            step2SubHeader2: "cs-advancedSearch-step2-subheader2",
            step2SubHeader2Label : "cs-advancedSearch-step2-subheader2-label",
            step2SubHeader2Note1 : "cs-advancedSearch-step2-subheader2-note1",
            step2SubHeader2AndOr : "cs-advancedSearch-step2-subheader2-andOr",
            step2SubHeader2Note2 : "cs-advancedSearch-step2-subheader2-note2",
            searchFields : "cs-advancedSearch-searchFields"
        },
        resources: {
            template: cspace.resourceSpecExpander({
                fetchClass: "fastTemplate",
                url: "%webapp/html/components/AdvancedSearchTemplate.html",
                options: {
                    dataType: "html"
                }
            })
        },
        invokers: {
            initSearchFields: {
                funcName: "cspace.advancedSearch.initSearchFields",
                args: ["{advancedSearch}", "{instantiator}", "{arguments}.0"]
            },
            search: {
                funcName: "cspace.advancedSearch.search",
                args: ["{advancedSearch}.events.onSearch", "{advancedSearch}.model", "{searchFields}.model"]
            },
            toggle: {
                funcName: "cspace.advancedSearch.toggle",
                args: ["{advancedSearch}.toggleControls", "{advancedSearch}.events.afterToggle"]
            },
            updateSearchHistory: "cspace.advancedSearch.updateSearchHistory"
        },
        strings: {},
        parentBundle: "{globalBundle}",
        finalInitFunction: "cspace.advancedSearch.finalInit",
        postInitFunction: "cspace.advancedSearch.postInit",
        preInitFunction: "cspace.advancedSearch.preInit"
    });

    cspace.advancedSearch.toggle = function (toggleControls, event) {
        toggleControls(false);
        event.fire();
    };

    var transformSearchModel = function (keywordModel, rules) {
        return fluid.model.transformWithRules(fluid.copy(keywordModel), rules);
    };

    cspace.advancedSearch.search = function (searchEvent, keywordModel, fieldsModel) {
        var searchModel = {};
        var rules = {
            "recordType": "recordType",
            "keywords": "keywords"
        };
        if (fieldsModel) {
            rules.operation = "operation";
            searchModel.fields = fluid.copy(fieldsModel);
        }
        fluid.merge(null, searchModel, transformSearchModel(keywordModel, rules));
        searchEvent.fire(searchModel)
    };

    cspace.advancedSearch.initSearchFields = function (that, instantiator, options) {
        if (that.searchFields) {
            instantiator.clearComponent(that, ["searchFields"]);
        }
        that.options.searchFields = that.options.searchFields || {};
        var defaultModel = fluid.copy(that.options.defaultFieldsModel);
        delete that.options.defaultFieldsModel;
        var model = defaultModel || cspace.util.getBeanValue({}, options.recordType, options.uischema);
        var applier = fluid.makeChangeApplier(model, {thin: true});
        that.options.searchFields = {
            model: model,
            applier: applier,
            schema: options.uischema
        };
        that.options.components.searchFields = {
            type: "cspace.advancedSearch.searchFields",
            container: "{advancedSearch}.dom.searchFields",
            options: {
                uispec: options.uispec,
                applier: "{advancedSearch}.options.searchFields.applier",
                model: "{advancedSearch}.options.searchFields.model",
                recordType: options.recordType,
                resources: {
                    template: options.template
                }
            }
        };
        fluid.initDependent(that, "searchFields", instantiator);
        that.events.afterSearchFieldsInit.fire();
    };

    cspace.advancedSearch.preInit = function (that) {
        cspace.util.preInitMergeListeners(that.options, {
            afterFetch: function (options) {
                that.initSearchFields(options);
            },
            recordTypeChanged: function () {
                that.locate("searchFields").hide();
            },
            afterSearchFieldsInit: function () {
                that.locate("searchFields").show();
            },
            onSearch: function (searchModel) {
                that.toggleControls(true);
            },
            afterSearch: function (searchModel) {
                that.updateSearchHistory(searchModel);
            }
        });
    };

    cspace.advancedSearch.postInit = function (that) {
        that.applier.modelChanged.addListener("recordType", function () {
            that.events.recordTypeChanged.fire(that.model.recordType);
        });
    };

    cspace.advancedSearch.finalInit = function (that) {
        that.toggleControls = function (hideSteps) {
            that.locate("step1").add(that.locate("step2"))[hideSteps ? "hide" : "show"]();
            that.locate("toggle")[hideSteps ? "show" : "hide"]();
        };
        that.refreshView();
    };

    cspace.advancedSearch.produceTree = function (that) {
        var tree = {
            advancedSearch: {decorators: {"addClass": "{styles}.advancedSearch"}},
            step2SubHeader1: {decorators: {"addClass": "{styles}.step2SubHeader1"}},
            step2SubHeader2: {decorators: {"addClass": "{styles}.step2SubHeader2"}},
            step1: {decorators: {"addClass": "{styles}.step1"}},
            step1Header: {decorators: {"addClass": "{styles}.step1Header"}},
            step1Label: {
                decorators: {"addClass": "{styles}.step1Label"},
                messagekey: "advancedSearch-step1Label"
            },
            step1Name: {
                decorators: {"addClass": "{styles}.step1Name"},
                messagekey: "advancedSearch-step1Name"
            },
            step2: {decorators: {"addClass": "{styles}.step2"}},
            step2Header: {decorators: {"addClass": "{styles}.step2Header"}},
            step2Label: {
                decorators: {"addClass": "{styles}.step2Label"},
                messagekey: "advancedSearch-step2Label"
            },
            step2Name: {
                decorators: {"addClass": "{styles}.step2Name"},
                messagekey: "advancedSearch-step2Name"
            },
            step2SubHeader1Label: {
                decorators: {"addClass": "{styles}.step2SubHeader1Label"},
                messagekey: "advancedSearch-step2SubHeader1Label"
            },
            step2SubHeader1Note: {
                decorators: {"addClass": "{styles}.step2SubHeader1Note"},
                messagekey: "advancedSearch-step2SubHeader1Note"
            },
            step2SubHeader2Label: {
                decorators: {"addClass": "{styles}.step2SubHeader2Label"},
                messagekey: "advancedSearch-step2SubHeader2Label"
            },
            step2SubHeader2Note1: {
                decorators: {"addClass": "{styles}.step2SubHeader2Note1"},
                messagekey: "advancedSearch-step2SubHeader2Note1"
            },
            step2SubHeader2Note2: {
                decorators: {"addClass": "{styles}.step2SubHeader2Note2"},
                messagekey: "advancedSearch-step2SubHeader2Note2"
            },
            step2SubHeader2AndOr: {
                optionnames: "${andOrNames}",
                optionlist: "${andOrList}",
                selection: "${operation}",
                decorators: {"addClass": "{styles}.step2SubHeader2AndOr"}
            },
            query: {
                value: "${keywords}",
                decorators: {"addClass": "{styles}.query"}
            },
            searchButton: {
                decorators: [{
                    type: "attrs",
                    attributes: {
                        value: that.options.parentBundle.messageBase["advancedSearch-searchButton"]
                    }
                }, {
                    type: "jQuery",
                    func: "click",
                    args: that.search
                }, {
                    addClass: "{styles}.searchButton"
                }]
            },
            toggle: {
                decorators: [{
                    type: "attrs",
                    attributes: {
                        value: that.options.parentBundle.messageBase["advancedSearch-toggle"]
                    }
                }, {
                    type: "jQuery",
                    func: "click",
                    args: that.toggle
                }, {
                    addClass: "{styles}.toggle"
                }]
            },
            searchFields: {decorators: {addClass: "{styles}.searchFields"}}
        };
        tree = $.extend(tree, that.recordTypeSelector.produceComponent());
        // TODO: This is a hack, recordTypeSelector's selection can't be bound.
        if (!that.model.recordType) {
            that.applier.requestChange("recordType", tree.recordTypeSelect.selection);
        }
        tree.recordTypeSelect.selection = "${recordType}";
        tree.recordTypeSelect.decorators = tree.recordTypeSelect.decorators ?
            tree.recordTypeSelect.decorators.concat([{"addClass": "{styles}.recordTypeSelect"}]) : [{"addClass": "{styles}.recordTypeSelect"}];
        return tree;
    };

    fluid.fetchResources.primeCacheFromResources("cspace.advancedSearch");

    cspace.advancedSearch.buildAndOrNames = function (messageBase) {
        return fluid.transform(["or", "and"], function (value) {
            return messageBase["advancedSearch-" + value];
        });
    };

    fluid.defaults("cspace.advancedSearch.searchFields", {
        gradeNames: ["autoInit", "fluid.rendererComponent"],
        produceTree: "cspace.advancedSearch.searchFields.produceTree",
        mergePolicy: {
            model: "preserve",
            applier: "nomerge",
            "rendererOptions.instantiator": "nomerge",
            "rendererOptions.parentComponent": "nomerge",
            "rendererFnOptions.uispec": "uispec",
            "rendererOptions.applier": "applier",
            uispec: "noexpand",
            schema: "nomerge"
        },
        renderOnInit: true,
        rendererFnOptions: {
            cutpointGenerator: "cspace.advancedSearch.searchFields.cutPointGenerator"
        },
        rendererOptions: {
            instantiator: "{instantiator}",
            parentComponent: "{searchFields}"
        },
        strings: {},
        parentBundle: "{globalBundle}"
    });

    cspace.advancedSearch.searchFields.produceTree = function (that) {
        return that.options.uispec;
    };

    cspace.advancedSearch.searchFields.cutPointGenerator = function (selectors, options) {
        return cspace.renderUtils.cutpointsFromUISpec(options.uispec);
    };

    fluid.defaults("cspace.advancedSearch.fetcher", {
        gradeNames: ["autoInit", "fluid.eventedComponent"],
        preInitFunction: "cspace.advancedSearch.fetcher.preInit",
        resourceSpec: {
            template: {
                href: cspace.componentUrlBuilder("%webapp/html/components/SearchFieldsTemplate-%recordType.html"),
                options: {
                    dataType: "html",
                    forceCache: true
                }
            },
            uispec: {
                href: cspace.componentUrlBuilder("%tenant/%tname/%recordType-search/uispec"),
                options: {
                    dataType: "json",
                    forceCache: true
                }
            },
            uischema: {
                href: cspace.componentUrlBuilder("%tenant/%tname/%recordType-search/uischema"),
                options: {
                    dataType: "json",
                    forceCache: true
                }
            }
        },
        events: {
            afterFetch: null
        },
        invokers: {
            displayErrorMessage: "cspace.util.displayErrorMessage",
            lookupMessage: "cspace.util.lookupMessage"
        }
    });

    cspace.advancedSearch.fetcher.preInit = function (that) {
        that.fetch = function (recordType) {
            var resourceSpec = fluid.copy(that.options.resourceSpec);
            fluid.each(resourceSpec, function (spec) {
                spec.href = fluid.stringTemplate(spec.href, {recordType: recordType});
                spec.options.error = cspace.util.provideErrorCallback(that, spec.href, "errorFetching");
                spec.options.success = function (data) {
                    if (!data) {
                        that.displayErrorMessage(fluid.stringTemplate(that.lookupMessage("emptyResponse"), {
                            url: spec.href
                        }));
                        return;
                    }
                    if (data.isError === true) {
                        fluid.each(data.messages, function (message) {
                            that.displayErrorMessage(message);
                        });
                        return;
                    }
                };
            });
            fluid.fetchResources(resourceSpec, function () {
                that.events.afterFetch.fire({
                    template: resourceSpec.template,
                    uispec: resourceSpec.uispec.resourceText,
                    uischema: resourceSpec.uischema.resourceText,
                    recordType: recordType
                });
            });
        };

        that.options.listeners = {
            fetchOn: that.fetch
        };
    };

})(jQuery, fluid);<|endoftext|>


<commit_before>const ISysProxy = require('./interface');
const {exec} = require('../../helpers/shell');

const DARWIN_PROXY_TYPE_SOCKS = 0;
const DARWIN_PROXY_TYPE_HTTP = 1;
const DARWIN_PROXY_TYPE_PAC = 2;

/**
 * List all services
 *   networksetup -listallnetworkservices
 *
 * Proxy Bypass
 *   networksetup -getproxybypassdomains <networkservice>
 *   networksetup -setproxybypassdomains <networkservice> <domain1> [domain2] [...]
 *
 * Global Socks5
 *   networksetup -getsocksfirewallproxy <networkservice>
 *   networksetup -setsocksfirewallproxy <networkservice> <domain> <port number>
 *   networksetup -setsocksfirewallproxystate <networkservice> <on off>
 *
 * Global HTTP
 *   networksetup -getwebproxy <networkservice>
 *   networksetup -setwebproxy <networkservice> <domain> <port number>
 *   networksetup -setwebproxystate <networkservice> <on off>
 *
 * PAC mode
 *   networksetup -getautoproxyurl <networkservice>
 *   networksetup -setautoproxyurl <networkservice> <url>
 *   networksetup -setautoproxystate <networkservice> <on off>
 */
module.exports = class DarwinSysProxy extends ISysProxy {

  constructor() {
    super();
    this._services = [];
    this._backups = {};
    this.init();
  }

  async init() {
    this._services = await this._getServices();
    for (const service of this._services) {
      this._backups[service] = {
        socks: await this._getSysSocksProxy(service),
        http: await this._getSysHTTPProxy(service),
        pac: await this._getSysPAC(service),
        bypass: await this._getSysProxyBypass(service)
      };
    }
  }

  getServices() {
    return this._services;
  }

  async setSocksProxy(service, host, port) {
    const enabled = !!(host && port);
    await this._setSysProxy(DARWIN_PROXY_TYPE_SOCKS, service, {enabled, host, port});
  }

  async restoreSocksProxy(service) {
    await this._setSysProxy(DARWIN_PROXY_TYPE_SOCKS, service, this._backups[service].socks);
  }

  async setHTTPProxy(service, host, port) {
    const enabled = !!(host && port);
    await this._setSysProxy(DARWIN_PROXY_TYPE_HTTP, service, {enabled, host, port});
  }

  async restoreHTTPProxy(service) {
    await this._setSysProxy(DARWIN_PROXY_TYPE_HTTP, service, this._backups[service].http);
  }

  async setPAC(service, url) {
    const enabled = !!(url);
    await this._setSysProxy(DARWIN_PROXY_TYPE_PAC, service, {enabled, url});
  }

  async restorePAC(service) {
    await this._setSysProxy(DARWIN_PROXY_TYPE_PAC, service, this._backups[service].pac);
  }

  async setBypass(service, domains) {
    await this._setSysProxyBypass(service, domains);
  }

  async restoreByPass(service) {
    await this._setSysProxyBypass(service, this._backups[service].bypass);
  }

  // privates

  async _getServices() {
    const {stdout} = await exec('networksetup -listallnetworkservices');
    return stdout.split('\n').slice(1, -1);
  }

  async _getSysSocksProxy(service) {
    return this._getSysProxy(DARWIN_PROXY_TYPE_SOCKS, service);
  }

  async _getSysHTTPProxy(service) {
    return this._getSysProxy(DARWIN_PROXY_TYPE_HTTP, service);
  }

  async _getSysPAC(service) {
    return this._getSysProxy(DARWIN_PROXY_TYPE_PAC, service);
  }

  async _getSysProxy(type, service) {
    const cmd = {
      [DARWIN_PROXY_TYPE_SOCKS]: 'getsocksfirewallproxy',
      [DARWIN_PROXY_TYPE_HTTP]: 'getwebproxy',
      [DARWIN_PROXY_TYPE_PAC]: 'getautoproxyurl'
    }[type];
    const {stdout} = await exec(`networksetup -${cmd} "${service}"`);
    const lines = stdout.split('\n').slice(0, -1);

    const obj = {};
    for (const line of lines) {
      const [key, value] = line.split(': ');
      obj[key.trim()] = value.trim();
    }

    const ret = {
      enabled: obj['Enabled'] === 'Yes',
      host: obj['Server'],
      port: obj['Port'] === '0' ? '' : obj['Port'],
      url: obj['URL'] === '(null)' ? '' : obj['URL'] // for PAC
    };

    // trim all [key]: undefined
    for (const key of Object.keys(ret)) {
      if (ret[key] === undefined) {
        delete ret[key];
      }
    }
    return ret;
  }

  async _getSysProxyBypass(service) {
    const {stdout} = await exec(`networksetup -getproxybypassdomains "${service}"`);
    const domains = stdout.split('\n').slice(0, -1);
    return domains.filter((domain) => domain.indexOf('There aren\'t') !== 0);
  }

  async _setSysProxy(type, service, {enabled, host, port, url}) {
    const cmds = [];
    switch (type) {
      case DARWIN_PROXY_TYPE_SOCKS:
        if (host && port) {
          cmds.push(`networksetup -setsocksfirewallproxy "${service}" ${host} ${port}`);
        }
        cmds.push(`networksetup -setsocksfirewallproxystate "${service}" ${enabled ? 'on' : 'off'}`);
        break;
      case DARWIN_PROXY_TYPE_HTTP:
        if (host && port) {
          cmds.push(`networksetup -setwebproxy "${service}" ${host} ${port}`);
        }
        cmds.push(`networksetup -setwebproxystate "${service}" ${enabled ? 'on' : 'off'}`);
        break;
      case DARWIN_PROXY_TYPE_PAC:
        if (url) {
          cmds.push(`networksetup -setautoproxyurl "${service}" ${url}`);
        }
        cmds.push(`networksetup -setautoproxystate "${service}" ${enabled ? 'on' : 'off'}`);
        break;
      default:
        break;
    }
    const codes = [];
    for (const cmd of cmds) {
      codes.push((await exec(cmd.trim())).code);
    }
    if (codes.some((code) => code !== 0)) {
      const name = {
        [DARWIN_PROXY_TYPE_SOCKS]: 'Socks Proxy',
        [DARWIN_PROXY_TYPE_HTTP]: 'HTTP Proxy',
        [DARWIN_PROXY_TYPE_PAC]: 'PAC'
      }[type];
      throw Error(`fail to set ${name} to: ${service}, maybe require root privileges!`);
    }
  }

  async _setSysProxyBypass(service, domains = []) {
    if (domains.length > 0) {
      const {code} = await exec(`networksetup -setproxybypassdomains "${service}" ${domains.join(' ')}`);
      if (code !== 0) {
        throw Error(`fail to set bypass to: ${service}, maybe require root privileges!`);
      }
    }
  }

};
<commit_msg>chore(darwin): remove darwin.legacy.js<commit_after><|endoftext|>