<commit_before>//
// Copyright (c) 2013-2016 SKYARCH NETWORKS INC.
//
// This software is released under the MIT License.
//
// http://opensource.org/licenses/mit-license.php
//

(function () {
  "use strict";
  var modal = require('modal');

  //  ----------------------------- variables
  var queryString = require('query-string').parse(location.search);

  new Vue({
    el: '#indexElement',
    data: {
      key_select: null,
      creating: false,
      params: {
        log_directory: null,
        access_key: null,
        secret_access_key: null,
        aws_region: null,
        keypair_name: null,
        keypair_value: null
      },
    },
    methods: {
      onFileChange: function (e) {
          var files = e.target.files || e.dataTransfer.files;
          if (!files.length) return;
          this.createFile(files[0]);
      },
      createFile: function(file) {
          var reader = new FileReader();
          var vm = this.params;

          reader.onload = function (e) {
              vm.keypair_value = e.target.result;
          };
          reader.readAsText(file);

          vm.keypair_name = file.name.replace(/\.\w+$/, '');
          console.log(vm);
      },
      removeFile: function (e) {
          e.preventDefault();
          var vm = this.params;
          modal.Confirm(t('app_settings.title.setup'), t('app_settings.msg.delete_file', {name: vm.keypair_name}), 'danger').done(function () {
            vm.keypair_name = null;
            vm.keypair_value = null;
          });

      },
      create_key: function() {
        event.preventDefault();
        var params = this.params;
        var name_file;
        modal.Confirm(t('app_settings.title.setup'), t('ec2_private_keys.confirm.create')).then(function () {
          return modal.Prompt(t('app_settings.title.setup'), t('key_pairs.name'));
        }).then(function (name) {
          if(!name){
            modal.Alert(t('app_settings.title.setup'), t('ec2_private_keys.msg.please_name'), 'danger');
            return;
          }
          name_file = name;
          return $.ajax({
            url: '/app_settings/generate_key',
            type: 'POST',
            data: {
              name:       name,
              region:     params.aws_region,
              access_key: params.access_key,
              secret_access_key: params.secret_access_key,
            },
          });

        }).done(function (key) {
          params.keypair_name = name_file;
          params.keypair_value = key.key_material;
          this.key_select = 2;

          // download file.
          var file = new File([key.key_material], name_file + '.pem');
          var url = window.URL.createObjectURL(file);
          var a = document.createElement('a');
          a.href = url;
          a.setAttribute('download', file.name);
          document.body.appendChild(a);
          a.click();
        }).fail(function (xhr) {
          modal.Alert(t('app_settings.title.setup'), xhr.responseText, 'danger');
        });
      },
      create: function()  {
        event.preventDefault();
        var self = this;
        self.creating = true;

        create(self.params).done(function (data) {
          chef_create().done(function (data) {
            update_creating_chefserver_progress(data);
            watch_chef_create_progress();
          });
        }).fail(function () {
          self.creating = false;
        });
      }

    },
    computed: {
      keysExists: function () {
        var self = this;
        return (self.params.access_key && self.params.secret_access_key && self.params.aws_region);
      },
      required_filed: function () {
        var self = this;
        return (self.params.access_key &&
          self.params.secret_access_key &&
          self.params.aws_region &&
          self.params.keypair_name &&
          self.params.keypair_value
        );
      }
    },
    ready: function () {
      introJs();
        // The rest of the code
        $("#flexi_form_start").click(function() {
            introJs().start().onbeforechange(function(targetElement) {
              $(".steps").hide();
              $(".left").css("float", "left");
              $("input").removeClass("error");
              $(".right").hide();
              switch($(targetElement).attr("data-step")) {
                case "2":
                  $(".flexi_form").hide();
                  $(targetElement).show();
                  break;
                case "3":
                  $("input").addClass("error");
                  $(targetElement).show();
                  break;
                case "4":
                  $(".left").css("float", "none");
                  $(targetElement).show();
                  break;
                case "5":
                  $(".right").show();
                  $(targetElement).show();
                  break;
              }
            });
          });

    }
  });

  var endpoint_base = '/app_settings';
  var inputs_selector = '#app-settings-form input[type=text],input[type=password],select,textarea';

  //  -------------------------------- ajax methods
  var create = function (settings) {

    return $.ajax({
      url: endpoint_base,
      type: 'POST',
      data: {
        settings: JSON.stringify(settings)
      },
    }).fail(modal.AlertForAjaxStdError());
  };

  var chef_create = function () {
    var stack_name = $('#chef_stack_name').val();

    return $.ajax({
      url: endpoint_base + '/chef_create',
      type: 'POST',
      data: {
        stack_name: stack_name,
      },
      dataType: "json",

    }).fail(modal.AlertForAjaxStdError());
  };

  //  --------------------------------  utility methods
  var is_fill_input = function() {
    var set = get_settings();
    for (var i in set) {
      if (set[i] === '') {
        return false;
      }
    }
    return true;
  };

  //  inputが全部埋まっていれば btn をenableにする。
  //  全部埋まっていなければdisableにする
  var switch_btn_enable = function (btn) {
    if (is_fill_input()) {
      btn.removeAttr('disabled');
    } else {
      btn.attr('disabled', 'disabled');
    }
  };

  var watch_chef_create_progress = function () {
    // TODO
    $('#btn-create-chefserver').hide();
    $('.create-chefserver').show();

    var ws = ws_connector('chef_server_deployment', 'status');
    ws.onmessage = function (msg) {
      var parsed = JSON.parse(msg.data);

      update_creating_chefserver_progress(parsed);
    };
  };

  var update_creating_chefserver_progress = function (data) {
    var progress       = $("#progress-create-chefserver");
    var progress_bar   = progress.children(".progress-bar");
    var progress_alert = $("#alert-create-chefserver");
    var current_percentage = parseInt( progress_bar.attr("area-valuenow") );

    progress_alert.text(data.message);
    // 進捗していればプログレスバーを進める
    if (data.percentage !== null && parseInt(data.percentage) > current_percentage ) {
      progress_bar.attr("style", "width: " + data.percentage + "%").attr("area-valuenow", data.percentage);
    }

    if (data.status === "complete") {
      progress.removeClass("progress-bar-striped active");
      progress_bar.removeClass("progress-bar-info").addClass("progress-bar-success");
      progress_alert.removeClass("alert-info").addClass("alert-success");

      $("#done-appsetting").removeClass("disabled").removeAttr("disabled");
      $("#wrapper").removeClass('toggled');
      $("#deploy").addClass('in');
      $("#signup").addClass('in');
    }
    else if (data.status === "error") {
      progress.removeClass("progress-bar-striped active");
      progress_bar.removeClass("progress-bar-info").addClass("progress-bar-danger");
      progress_alert.removeClass("alert-info").addClass("alert-danger");
    }
  };

})();
<commit_msg>Set creating to true when create function is called<commit_after>//
// Copyright (c) 2013-2016 SKYARCH NETWORKS INC.
//
// This software is released under the MIT License.
//
// http://opensource.org/licenses/mit-license.php
//

(function () {
  "use strict";
  var modal = require('modal');

  //  ----------------------------- variables
  var queryString = require('query-string').parse(location.search);

  new Vue({
    el: '#indexElement',
    data: {
      key_select: null,
      creating: false,
      params: {
        log_directory: null,
        access_key: null,
        secret_access_key: null,
        aws_region: null,
        keypair_name: null,
        keypair_value: null
      },
    },
    methods: {
      onFileChange: function (e) {
          var files = e.target.files || e.dataTransfer.files;
          if (!files.length) return;
          this.createFile(files[0]);
      },
      createFile: function(file) {
          var reader = new FileReader();
          var vm = this.params;

          reader.onload = function (e) {
              vm.keypair_value = e.target.result;
          };
          reader.readAsText(file);

          vm.keypair_name = file.name.replace(/\.\w+$/, '');
          console.log(vm);
      },
      removeFile: function (e) {
          e.preventDefault();
          var vm = this.params;
          modal.Confirm(t('app_settings.title.setup'), t('app_settings.msg.delete_file', {name: vm.keypair_name}), 'danger').done(function () {
            vm.keypair_name = null;
            vm.keypair_value = null;
          });

      },
      create_key: function() {
        event.preventDefault();
        var params = this.params;
        var name_file;
        modal.Confirm(t('app_settings.title.setup'), t('ec2_private_keys.confirm.create')).then(function () {
          return modal.Prompt(t('app_settings.title.setup'), t('key_pairs.name'));
        }).then(function (name) {
          if(!name){
            modal.Alert(t('app_settings.title.setup'), t('ec2_private_keys.msg.please_name'), 'danger');
            return;
          }
          name_file = name;
          return $.ajax({
            url: '/app_settings/generate_key',
            type: 'POST',
            data: {
              name:       name,
              region:     params.aws_region,
              access_key: params.access_key,
              secret_access_key: params.secret_access_key,
            },
          });

        }).done(function (key) {
          params.keypair_name = name_file;
          params.keypair_value = key.key_material;
          this.key_select = 2;

          // download file.
          var file = new File([key.key_material], name_file + '.pem');
          var url = window.URL.createObjectURL(file);
          var a = document.createElement('a');
          a.href = url;
          a.setAttribute('download', file.name);
          document.body.appendChild(a);
          a.click();
        }).fail(function (xhr) {
          modal.Alert(t('app_settings.title.setup'), xhr.responseText, 'danger');
        });
      },
      create: function()  {
        event.preventDefault();
        var self = this;

        create(self.params).done(function (data) {
          chef_create().done(function (data) {
            self.creating = true;
            update_creating_chefserver_progress(data);
            watch_chef_create_progress();
          });
        }).fail(function () {
          self.creating = false;
        });
      }

    },
    computed: {
      keysExists: function () {
        var self = this;
        return (self.params.access_key && self.params.secret_access_key && self.params.aws_region);
      },
      required_filed: function () {
        var self = this;
        return (self.params.access_key &&
          self.params.secret_access_key &&
          self.params.aws_region &&
          self.params.keypair_name &&
          self.params.keypair_value
        );
      }
    },
    ready: function () {
      introJs();
        // The rest of the code
        $("#flexi_form_start").click(function() {
            introJs().start().onbeforechange(function(targetElement) {
              $(".steps").hide();
              $(".left").css("float", "left");
              $("input").removeClass("error");
              $(".right").hide();
              switch($(targetElement).attr("data-step")) {
                case "2":
                  $(".flexi_form").hide();
                  $(targetElement).show();
                  break;
                case "3":
                  $("input").addClass("error");
                  $(targetElement).show();
                  break;
                case "4":
                  $(".left").css("float", "none");
                  $(targetElement).show();
                  break;
                case "5":
                  $(".right").show();
                  $(targetElement).show();
                  break;
              }
            });
          });

    }
  });

  var endpoint_base = '/app_settings';
  var inputs_selector = '#app-settings-form input[type=text],input[type=password],select,textarea';

  //  -------------------------------- ajax methods
  var create = function (settings) {

    return $.ajax({
      url: endpoint_base,
      type: 'POST',
      data: {
        settings: JSON.stringify(settings)
      },
    }).fail(modal.AlertForAjaxStdError());
  };

  var chef_create = function () {
    var stack_name = $('#chef_stack_name').val();

    return $.ajax({
      url: endpoint_base + '/chef_create',
      type: 'POST',
      data: {
        stack_name: stack_name,
      },
      dataType: "json",

    }).fail(modal.AlertForAjaxStdError());
  };

  //  --------------------------------  utility methods
  var is_fill_input = function() {
    var set = get_settings();
    for (var i in set) {
      if (set[i] === '') {
        return false;
      }
    }
    return true;
  };

  //  inputが全部埋まっていれば btn をenableにする。
  //  全部埋まっていなければdisableにする
  var switch_btn_enable = function (btn) {
    if (is_fill_input()) {
      btn.removeAttr('disabled');
    } else {
      btn.attr('disabled', 'disabled');
    }
  };

  var watch_chef_create_progress = function () {
    // TODO
    $('#btn-create-chefserver').hide();
    $('.create-chefserver').show();

    var ws = ws_connector('chef_server_deployment', 'status');
    ws.onmessage = function (msg) {
      var parsed = JSON.parse(msg.data);

      update_creating_chefserver_progress(parsed);
    };
  };

  var update_creating_chefserver_progress = function (data) {
    var progress       = $("#progress-create-chefserver");
    var progress_bar   = progress.children(".progress-bar");
    var progress_alert = $("#alert-create-chefserver");
    var current_percentage = parseInt( progress_bar.attr("area-valuenow") );

    progress_alert.text(data.message);
    // 進捗していればプログレスバーを進める
    if (data.percentage !== null && parseInt(data.percentage) > current_percentage ) {
      progress_bar.attr("style", "width: " + data.percentage + "%").attr("area-valuenow", data.percentage);
    }

    if (data.status === "complete") {
      progress.removeClass("progress-bar-striped active");
      progress_bar.removeClass("progress-bar-info").addClass("progress-bar-success");
      progress_alert.removeClass("alert-info").addClass("alert-success");

      $("#done-appsetting").removeClass("disabled").removeAttr("disabled");
      $("#wrapper").removeClass('toggled');
      $("#deploy").addClass('in');
      $("#signup").addClass('in');
    }
    else if (data.status === "error") {
      progress.removeClass("progress-bar-striped active");
      progress_bar.removeClass("progress-bar-info").addClass("progress-bar-danger");
      progress_alert.removeClass("alert-info").addClass("alert-danger");
    }
  };

})();
<|endoftext|>


<commit_before>export { AsyncWorker_Proxy as Proxy };

import * as Pool from "../Pool.js";
import * as Recyclable from "../Recyclable.js";
import { PromiseResolveReject } from "./AsyncWorker_PromiseResolveReject.js";
import { processingId_Resulter_Map } from "./AsyncWorker_processingId_Resulter_Map.js";
import { Resulter } from "./AsyncWorker_Resulter.js";

/**
 * Hold the worker and its related promise map. It is a wrapper of a neural network
 * web worker for handling and communicating easily.
 *
 * @member {string} workerModuleURL
 *   The (absolute) javascript module URL which will be loaded (asynchronously) by
 * worker body (stub).
 *
 * @member {Worker} worker
 *   The worker.
 *
 * @member {number} processingId_next
 *   The next processing id. Zero means no command has been sent. Every
 * postCommand_and_expectResult() call will use a new id.
 *
 * @member {processingId_Resulter_Map} the_processingId_Resulter_Map
 *   Every worker has a result pending promise map. The key of the map is processing
 * id. The value of the map is a AsyncWorker.Resulter.
 *
 */
class AsyncWorker_Proxy extends Recyclable.Root {

  /**
   * Used as default AsyncWorker.Proxy provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "AsyncWorker.Proxy.Pool",
    AsyncWorker_Proxy, AsyncWorker_Proxy.setAsConstructor );

  /** */
  constructor( workerModuleURL ) {
    super();
    AsyncWorker_Proxy.setAsConstructor_self.call( this, workerModuleURL );
  }

  /** @override */
  static setAsConstructor() {
    super.setAsConstructor();
    AsyncWorker_Proxy.setAsConstructor_self.call( this, workerModuleURL );
    return this;
  }

  /** @override */
  static setAsConstructor_self( workerModuleURL ) {

    // Q: What if processingId become too large (e.g. infinity)?
    // A: Because Number.MAX_SAFE_INTEGER is pretty large (at least, 2 ** 52 ),
    //    it is not so easy to become out of bounds.
    //
    this.processingId_next = 0;

    if ( this.the_processingId_Resulter_Map )
      this.the_processingId_Resulter_Map.clear();
    else
      this.the_processingId_Resulter_Map = new processingId_Resulter_Map();

    AsyncWorker_Proxy.createWorker_byModuleURL.call( this, workerModuleURL );
  }

  /** @override */
  disposeResources() {

    if ( this.worker ) {
      // Note: No processingId, because this command needs not return value.
      this.postCommandArgs( "disposeResources" );
      this.worker = null;
    }

    this.workerOptions = undefined;
    this.workerURL = undefined;
    this.workerModuleURL = undefined;

    this.the_processingId_Resulter_Map.clear();

    this.processingId_next = undefined;

    super.disposeResources();
  }

  /**
   * @param {AsyncWorker_Proxy} this
   *   The worker proxy.
   */
  static createWorker_byModuleURL( workerModuleURL ) {
    this.workerModuleURL = workerModuleURL;

    let workerDataURI
      = AsyncWorker_Proxy.create_WorkerBodyStub_Codes_DataURI( workerModuleURL );

    this.workerURL = workerDataURI;

    // Q: Why not use "module" type worker?
    // A: A "module" type worker can not use importScripts() to load global library.
    //    (e.g. tensorflow.js)
    //
    // On the other hand, a "classic" type worker can use both importScripts() and
    // import() to load global library and module.
    //
    this.workerOptions = null;

    this.worker = new Worker( this.workerURL, this.workerOptions );

    // Register callback from the web worker.
    this.worker.onmessage
      = AsyncWorker_Proxy.onmessage_from_AsyncWorker_Body.bind( this );
  }

  /**
   * Create a data URI representing the main (i.e. body) javascript file of web worker.
   * It is viewed as a classic javascript file (i.e. not an importable module). But
   * it will load specified workerModuleURL as a module.
   *
   * In module (non-classic) web worker, static import is available. But the function
   * importScripts() will not be avbailable. For solving this problem, using
   * classic (non-module) web worker so that some global library (e.g. tensorflow.js)
   * can be loaded by importScripts(). And use dynamic import() to load ourselves
   * modules because import() can be used in classic (non-module) script.
   *
   * @param {string} workerModuleURL
   *   An (absolute) URL to a javascript module file. It will be imported
   * (asynchronously) by this generated classic javascript file (as a dataURI).
   */
  static create_WorkerBodyStub_Codes_DataURI( workerModuleURL ) {

    // The codes do the following:
    //
    //   - Import the specified module URL.
    //   - Create a temporary message queue.
    //   - Collect all messages before
    //       AsyncWorker_Proxy.onmessage_from_AsyncWorker_Body() be registered
    //       as message handler.
    //
    let codes = ``
      + `import( "${workerModuleURL}" );\n`
      + `AsyncWorker_Body_temporaryMessageQueue = [];\n`
      + `onmessage = ( e ) => {\n`
      // + `  console.log( "Hello" );\n`
      // + `  console.log( e );\n`
      + `  AsyncWorker_Body_temporaryMessageQueue.push( e );\n`
      + `};\n`
      ;

    let workerDataURI
      = AsyncWorker_Proxy.createDataURI_byStringASCII( "text/javascript", codes );

    return workerDataURI;
  }

  /**
   * @param {string} strMimeType  The result mime type of the data URI.
   * @param {string} strASCII     The ASCII text to be embedded in data URI.
   *
   * @return {string} Return the data URI string.
   */
  static createDataURI_byStringASCII( strMimeType, strASCII ) {
    // let textEncoder = new TextEncoder();
    // let str_utf8 = textEncoder.encode( str );
    // let str_base64 = btoa( str_utf8 );
    let str_base64 = btoa( strASCII );
    let dataURI = `data:${strMimeType};base64,${str_base64}`;
    return dataURI;
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * and expect the final result.
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   *
   * @return {Promise}
   *   Return a promise resolved to the final value of the processing's resulter
   * from WorkerBody. (i.e. Only the Xxx of { done: true, value: Xxx } resolved.
   * All other intermediate result { done: false, value: Yyy } are discarded.)
   */
  createPromise_by_postCommandArgs( commandArgs, transferableObjectArray ) {
    let resulter = this.createResulter_by_postCommandArgs(
      commandArgs, transferableObjectArray );
    return resulter.untilDone();
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * and expect result.
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   *
   * @return {AsyncWorker.Resulter}
   *   Return an async generator for receving result from WorkerBody of the processing.
   */
  createResulter_by_postCommandArgs( commandArgs, transferableObjectArray ) {
    let processingId = this.processingId_next;
    ++this.processingId_next;

    // Prepare the processing's result's receiving queue before sending it.
    let resulter = this.the_processingId_Resulter_Map.createResulter_by_processingId(
      processingId );

    let processingId_commandArgs = [ processingId, ...commandArgs ];
    this.worker.postMessage( processingId_commandArgs, transferableObjectArray );
    return resulter;
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * without expecting result. (i.e. fire-and-forget)
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   */
  postCommandArgs( commandArgs, transferableObjectArray ) {
    let processingId_commandArgs = [ undefined, ...commandArgs ]; // no processingId.
    this.worker.postMessage( processingId_commandArgs, transferableObjectArray );
  }

  /**
   * Dispatch messages come from the owned web worker. Please register this method
   * as this WorkerProxy's Worker.onmessage.
   *
   * @param {AsyncWorker_Proxy} this
   *   The "this" should be binded to this AsyncWorker_Proxy object.
   */
  static onmessage_from_AsyncWorker_Body( e ) {

    // ( e.data == [ processingId, done, value ] )
    let [ processingId, done, value ] = e.data;

    this.the_processingId_Resulter_Map.resolve_or_reject_by_processingId_done_value(
      processingId, done, value );
  }

}
<commit_msg>postCommandArgs<commit_after>export { AsyncWorker_Proxy as Proxy };

import * as Pool from "../Pool.js";
import * as Recyclable from "../Recyclable.js";
import { PromiseResolveReject } from "./AsyncWorker_PromiseResolveReject.js";
import { processingId_Resulter_Map } from "./AsyncWorker_processingId_Resulter_Map.js";
import { Resulter } from "./AsyncWorker_Resulter.js";

/**
 * Hold the worker and its related promise map. It is a wrapper of a neural network
 * web worker for handling and communicating easily.
 *
 * @member {string} workerModuleURL
 *   The (absolute) javascript module URL which will be loaded (asynchronously) by
 * worker body (stub).
 *
 * @member {Worker} worker
 *   The worker.
 *
 * @member {number} processingId_next
 *   The next processing id. Zero means no command has been sent. Every
 * postCommand_and_expectResult() call will use a new id.
 *
 * @member {processingId_Resulter_Map} the_processingId_Resulter_Map
 *   Every worker has a result pending promise map. The key of the map is processing
 * id. The value of the map is a AsyncWorker.Resulter.
 *
 */
class AsyncWorker_Proxy extends Recyclable.Root {

  /**
   * Used as default AsyncWorker.Proxy provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "AsyncWorker.Proxy.Pool",
    AsyncWorker_Proxy, AsyncWorker_Proxy.setAsConstructor );

  /** */
  constructor( workerModuleURL ) {
    super();
    AsyncWorker_Proxy.setAsConstructor_self.call( this, workerModuleURL );
  }

  /** @override */
  static setAsConstructor() {
    super.setAsConstructor();
    AsyncWorker_Proxy.setAsConstructor_self.call( this, workerModuleURL );
    return this;
  }

  /** @override */
  static setAsConstructor_self( workerModuleURL ) {

    // Q: What if processingId become too large (e.g. infinity)?
    // A: Because Number.MAX_SAFE_INTEGER is pretty large (at least, 2 ** 52 ),
    //    it is not so easy to become out of bounds.
    //
    this.processingId_next = 0;

    if ( this.the_processingId_Resulter_Map )
      this.the_processingId_Resulter_Map.clear();
    else
      this.the_processingId_Resulter_Map = new processingId_Resulter_Map();

    AsyncWorker_Proxy.createWorker_byModuleURL.call( this, workerModuleURL );
  }

  /** @override */
  disposeResources() {

    if ( this.worker ) {
      // Note: No processingId, because this command needs not return value.
      this.postCommandArgs( [ "disposeResources" ] );
      this.worker = null;
    }

    this.workerOptions = undefined;
    this.workerURL = undefined;
    this.workerModuleURL = undefined;

    this.the_processingId_Resulter_Map.clear();

    this.processingId_next = undefined;

    super.disposeResources();
  }

  /**
   * @param {AsyncWorker_Proxy} this
   *   The worker proxy.
   */
  static createWorker_byModuleURL( workerModuleURL ) {
    this.workerModuleURL = workerModuleURL;

    let workerDataURI
      = AsyncWorker_Proxy.create_WorkerBodyStub_Codes_DataURI( workerModuleURL );

    this.workerURL = workerDataURI;

    // Q: Why not use "module" type worker?
    // A: A "module" type worker can not use importScripts() to load global library.
    //    (e.g. tensorflow.js)
    //
    // On the other hand, a "classic" type worker can use both importScripts() and
    // import() to load global library and module.
    //
    this.workerOptions = null;

    this.worker = new Worker( this.workerURL, this.workerOptions );

    // Register callback from the web worker.
    this.worker.onmessage
      = AsyncWorker_Proxy.onmessage_from_AsyncWorker_Body.bind( this );
  }

  /**
   * Create a data URI representing the main (i.e. body) javascript file of web worker.
   * It is viewed as a classic javascript file (i.e. not an importable module). But
   * it will load specified workerModuleURL as a module.
   *
   * In module (non-classic) web worker, static import is available. But the function
   * importScripts() will not be avbailable. For solving this problem, using
   * classic (non-module) web worker so that some global library (e.g. tensorflow.js)
   * can be loaded by importScripts(). And use dynamic import() to load ourselves
   * modules because import() can be used in classic (non-module) script.
   *
   * @param {string} workerModuleURL
   *   An (absolute) URL to a javascript module file. It will be imported
   * (asynchronously) by this generated classic javascript file (as a dataURI).
   */
  static create_WorkerBodyStub_Codes_DataURI( workerModuleURL ) {

    // The codes do the following:
    //
    //   - Import the specified module URL.
    //   - Create a temporary message queue.
    //   - Collect all messages before
    //       AsyncWorker_Proxy.onmessage_from_AsyncWorker_Body() be registered
    //       as message handler.
    //
    let codes = ``
      + `import( "${workerModuleURL}" );\n`
      + `AsyncWorker_Body_temporaryMessageQueue = [];\n`
      + `onmessage = ( e ) => {\n`
      // + `  console.log( "Hello" );\n`
      // + `  console.log( e );\n`
      + `  AsyncWorker_Body_temporaryMessageQueue.push( e );\n`
      + `};\n`
      ;

    let workerDataURI
      = AsyncWorker_Proxy.createDataURI_byStringASCII( "text/javascript", codes );

    return workerDataURI;
  }

  /**
   * @param {string} strMimeType  The result mime type of the data URI.
   * @param {string} strASCII     The ASCII text to be embedded in data URI.
   *
   * @return {string} Return the data URI string.
   */
  static createDataURI_byStringASCII( strMimeType, strASCII ) {
    // let textEncoder = new TextEncoder();
    // let str_utf8 = textEncoder.encode( str );
    // let str_base64 = btoa( str_utf8 );
    let str_base64 = btoa( strASCII );
    let dataURI = `data:${strMimeType};base64,${str_base64}`;
    return dataURI;
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * and expect the final result.
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   *
   * @return {Promise}
   *   Return a promise resolved to the final value of the processing's resulter
   * from WorkerBody. (i.e. Only the Xxx of { done: true, value: Xxx } resolved.
   * All other intermediate result { done: false, value: Yyy } are discarded.)
   */
  createPromise_by_postCommandArgs( commandArgs, transferableObjectArray ) {
    let resulter = this.createResulter_by_postCommandArgs(
      commandArgs, transferableObjectArray );
    return resulter.untilDone();
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * and expect result.
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   *
   * @return {AsyncWorker.Resulter}
   *   Return an async generator for receving result from WorkerBody of the processing.
   */
  createResulter_by_postCommandArgs( commandArgs, transferableObjectArray ) {
    let processingId = this.processingId_next;
    ++this.processingId_next;

    // Prepare the processing's result's receiving queue before sending it.
    let resulter = this.the_processingId_Resulter_Map.createResulter_by_processingId(
      processingId );

    let processingId_commandArgs = [ processingId, ...commandArgs ];
    this.worker.postMessage( processingId_commandArgs, transferableObjectArray );
    return resulter;
  }

  /**
   * Send command and args (perhaps, with transferable object array) to WorkerBody
   * without expecting result. (i.e. fire-and-forget)
   *
   * @param {Array} commandArgs
   *   An array (i.e. [ comand, ...args ]) which will be sent to the WorkerBody.
   *
   *   - The command is a string which is the WorkerBody's method function to be
   *       called.
   *
   *   - The args is an array which will be destructured into multiple arguments
   *       and passed into the WorkerBody's method function.
   *
   * @param {Array} transferableObjectArray
   *   The transferable object array when postMessage. It could be undefined (but
   * can not be null).
   */
  postCommandArgs( commandArgs, transferableObjectArray ) {
    let processingId_commandArgs = [ undefined, ...commandArgs ]; // no processingId.
    this.worker.postMessage( processingId_commandArgs, transferableObjectArray );
  }

  /**
   * Dispatch messages come from the owned web worker. Please register this method
   * as this WorkerProxy's Worker.onmessage.
   *
   * @param {AsyncWorker_Proxy} this
   *   The "this" should be binded to this AsyncWorker_Proxy object.
   */
  static onmessage_from_AsyncWorker_Body( e ) {

    // ( e.data == [ processingId, done, value ] )
    let [ processingId, done, value ] = e.data;

    this.the_processingId_Resulter_Map.resolve_or_reject_by_processingId_done_value(
      processingId, done, value );
  }

}
<|endoftext|>


<commit_before>class Ship {

  constructor(length, classification) {
    this.length = length;
    this.classification = classification;
    if (Ship.all === undefined) {
      Ship.all = [this];
    } else {
      Ship.all.push(this);
    }
  }

  cells() {
    let ship = $('#'+this.classification);
    let row = parseInt(ship[0].style.left)/32 + 13;
    let column = parseInt(ship[0].style.top)/32 + 4;
    let answer = [];

    if (ship.hasClass("vertical")){
      for(let i=0;i<this.length;i++){
        answer.push(column+'-'+row);
        column++;
      }
    } else {
      for(let i=0;i<this.length;i++){
        answer.push(column+'-'+row);
        row++;
      }
    }
    return answer;
  }

  on_board() {
    let ship = document.getElementById(this.classification);
    return ship.style.left !== "" && ship.style.left !== "0px";
  }

}

class Board {

  constructor() {
    this.ships = [new Ship(2, "patrol-boat"), new Ship(3, "destroyer"), new Ship(3, "submarine"), new Ship(4, "battleship"), new Ship(5, "aircraft-carrier")];
  }

  placed_ships() {
    let affirmatives = [];
    this.ships.forEach(ship => {
      if (ship.on_board()) {
        affirmatives.push(ship);
      }
    });
    return affirmatives;
  }

  occupiedPositions(){
    let positions = [];
    this.placed_ships().forEach(ship => {
      positions.push(ship.cells());
    });

    if (positions.length != 0) {
      return positions.reduce((a, b) => {
        return a.concat(b);
      });
    } else {
      return [];
    }
  }

  blockedPositions(ship){
    let positions = [];
    this.placed_ships().forEach(anchoredShip => {
      if (ship.classification == anchoredShip.classification) {
        return;
      }
      positions.push(anchoredShip.cells());
    });

    if (positions.length != 0) {
      return positions.reduce((a, b) => {
        return a.concat(b);
      });
    } else {
      return [];
    }
  }
}

function generateObstacles(ship, board){
  let obstacleArray = [];
  board.blockedPositions(ship).forEach(id => {
    obstacleArray.push({ obstacle: "#"+id, preventCollision: true })
  });
  return obstacleArray;
}

function rotate($ship) {
  if ($ship.hasClass('horizontal')) {
    $ship.removeClass('horizontal');
    $ship.addClass('vertical');
  } else {
    $ship.removeClass('vertical');
    $ship.addClass('horizontal');
  }
}

function checkOtherShips(ship, board){
  let answer = true;
  Ship.all.forEach(boat => {
    if (boat.classification === ship.id) {
      let flipped = [],
          first = boat.cells()[0],
          size = boat.cells().length,
          column = parseInt(first),
          row = parseInt(first.substr(2));

      if (ship.className.match(/\bhorizontal\b/)) {
        for(let i=0; i<size; i++) {
          flipped.push((column+i)+'-'+row);
        }
      } else {
        for(let i=0; i<size; i++) {
          flipped.push(column+'-'+(row+1));
        }
      }

      flipped.forEach(position => {
        if (board.blockedPositions(boat).includes(position)) {
          answer = false;
        }
      });
    }
  });
  return answer;
}

function checkBottomWallCollision(ship) {
  switch (ship.id) {
    case "patrol-boat":
      return parseInt(ship.style.top) <= 160;
      break;
    case "destroyer":
    case "submarine":
      return parseInt(ship.style.top) <= 128;
      break;
    case "battleship":
      return parseInt(ship.style.top) <= 96;
      break;
    case "aircraft-carrier":
      return parseInt(ship.style.top) <= 64;
  }
}

function checkRightWallCollision(ship) {
  switch (ship.id) {
    case "patrol-boat":
      return parseInt(ship.style.left) <= -128;
      break;
    case "destroyer":
    case "submarine":
      return parseInt(ship.style.left) <= -160;
      break;
    case "battleship":
      return parseInt(ship.style.left) <= -192;
      break;
    case "aircraft-carrier":
      return parseInt(ship.style.left) <= -224;
  }
}

let boardReady = (function(){
  let $patrol_boat = $('#patrol-boat'),
      $destroyer = $('#destroyer'),
      $submarine = $('#submarine'),
      $battleship = $('#battleship'),
      $aircraft_carrier = $('#aircraft-carrier'),
      board = new Board,
      obstacles;

  $('.ship').mousedown(function(){
    if (checkBottomWallCollision(this) && checkRightWallCollision(this) && checkOtherShips(this, board)){
      rotate($(this));
    }
  });

  $patrol_boat.draggable({
    grid: [32,32],
    start: (event, ui) => {
      let patroller = board.ships[0];
      obstacles = generateObstacles(patroller, board);
      $patrol_boat.draggable("option", "multipleCollisionInteractions", obstacles);
      $patrol_boat.draggable("option", "revert", "invalid");
    }
  });

  $destroyer.draggable({
    grid: [32,32],
    start: (event, ui) => {
      let destroyer = board.ships[1];
      obstacles = generateObstacles(destroyer, board);
      $destroyer.draggable("option", "multipleCollisionInteractions", obstacles);
      $destroyer.draggable("option", "revert", "invalid");
    }
  });

  $submarine.draggable({
    grid: [ 32,32 ],
    start: (event, ui) => {
      let submarine = board.ships[2];
      obstacles = generateObstacles(submarine, board);
      $submarine.draggable("option", "multipleCollisionInteractions", obstacles);
      $submarine.draggable("option", "revert", "invalid");
    }
  });

  $battleship.draggable({
    grid: [ 32,32 ],
    start: (event, ui) => {
      let battler = board.ships[3];
      obstacles = generateObstacles(battler, board);
      $battleship.draggable("option", "multipleCollisionInteractions", obstacles);
      $battleship.draggable("option", "revert", "invalid");
    }
  });

  $aircraft_carrier.draggable({
    grid: [ 32,32 ],
    start: (event, ui) => {
      let crafter = board.ships[4];
      obstacles = generateObstacles(crafter, board);
      $aircraft_carrier.draggable("option", "multipleCollisionInteractions", obstacles);
      $aircraft_carrier.draggable("option", "revert", "invalid");
    }
  });

  $('#board-setup').droppable({
    accept: ".ship",
    tolerance: "fit"
  });

});

$(document).ready(boardReady);
<commit_msg>Trim extra spaces<commit_after>class Ship {
  constructor(length, classification) {
    this.length = length;
    this.classification = classification;
    if (Ship.all === undefined) {
      Ship.all = [this];
    } else {
      Ship.all.push(this);
    }
  }

  cells() {
    let ship = $('#'+this.classification);
    let row = parseInt(ship[0].style.left)/32 + 13;
    let column = parseInt(ship[0].style.top)/32 + 4;
    let answer = [];

    if (ship.hasClass("vertical")){
      for(let i=0;i<this.length;i++){
        answer.push(column+'-'+row);
        column++;
      }
    } else {
      for(let i=0;i<this.length;i++){
        answer.push(column+'-'+row);
        row++;
      }
    }
    return answer;
  }

  on_board() {
    let ship = document.getElementById(this.classification);
    return ship.style.left !== "" && ship.style.left !== "0px";
  }
}

class Board {
  constructor() {
    this.ships = [new Ship(2, "patrol-boat"), new Ship(3, "destroyer"), new Ship(3, "submarine"), new Ship(4, "battleship"), new Ship(5, "aircraft-carrier")];
  }

  placed_ships() {
    let affirmatives = [];
    this.ships.forEach(ship => {
      if (ship.on_board()) {
        affirmatives.push(ship);
      }
    });
    return affirmatives;
  }

  occupiedPositions(){
    let positions = [];
    this.placed_ships().forEach(ship => {
      positions.push(ship.cells());
    });

    if (positions.length != 0) {
      return positions.reduce((a, b) => {
        return a.concat(b);
      });
    } else {
      return [];
    }
  }

  blockedPositions(ship){
    let positions = [];
    this.placed_ships().forEach(anchoredShip => {
      if (ship.classification == anchoredShip.classification) {
        return;
      }
      positions.push(anchoredShip.cells());
    });

    if (positions.length != 0) {
      return positions.reduce((a, b) => {
        return a.concat(b);
      });
    } else {
      return [];
    }
  }
}

function generateObstacles(ship, board){
  let obstacleArray = [];
  board.blockedPositions(ship).forEach(id => {
    obstacleArray.push({ obstacle: "#"+id, preventCollision: true })
  });
  return obstacleArray;
}

function rotate($ship) {
  if ($ship.hasClass('horizontal')) {
    $ship.removeClass('horizontal');
    $ship.addClass('vertical');
  } else {
    $ship.removeClass('vertical');
    $ship.addClass('horizontal');
  }
}

function checkBottomWallCollision(ship) {
  switch (ship.id) {
    case "patrol-boat":
      return parseInt(ship.style.top) <= 160;
      break;
    case "destroyer":
    case "submarine":
      return parseInt(ship.style.top) <= 128;
      break;
    case "battleship":
      return parseInt(ship.style.top) <= 96;
      break;
    case "aircraft-carrier":
      return parseInt(ship.style.top) <= 64;
  }
}

function checkRightWallCollision(ship) {
  switch (ship.id) {
    case "patrol-boat":
      return parseInt(ship.style.left) <= -128;
      break;
    case "destroyer":
    case "submarine":
      return parseInt(ship.style.left) <= -160;
      break;
    case "battleship":
      return parseInt(ship.style.left) <= -192;
      break;
    case "aircraft-carrier":
      return parseInt(ship.style.left) <= -224;
  }
}

function checkOtherShips(ship, board){
  let answer = true;
  Ship.all.forEach(boat => {
    if (boat.classification === ship.id) {
      let flipped = [],
          first = boat.cells()[0],
          size = boat.cells().length,
          column = parseInt(first),
          row = parseInt(first.substr(2));

      if (ship.className.match(/\bhorizontal\b/)) {
        for(let i=0; i<size; i++) {
          flipped.push((column+i)+'-'+row);
        }
      } else {
        for(let i=0; i<size; i++) {
          flipped.push(column+'-'+(row+1));
        }
      }

      flipped.forEach(position => {
        if (board.blockedPositions(boat).includes(position)) {
          answer = false;
        }
      });
    }
  });
  return answer;
}

let boardReady = (function(){
  let $patrol_boat = $('#patrol-boat'),
      $destroyer = $('#destroyer'),
      $submarine = $('#submarine'),
      $battleship = $('#battleship'),
      $aircraft_carrier = $('#aircraft-carrier'),
      board = new Board,
      obstacles;

  $('.ship').mousedown(function(){
    if (checkBottomWallCollision(this) && checkRightWallCollision(this) && checkOtherShips(this, board)){
      rotate($(this));
    }
  });

  $patrol_boat.draggable({
    grid: [32,32],
    start: (event, ui) => {
      let patroller = board.ships[0];
      obstacles = generateObstacles(patroller, board);
      $patrol_boat.draggable("option", "multipleCollisionInteractions", obstacles);
      $patrol_boat.draggable("option", "revert", "invalid");
    }
  });

  $destroyer.draggable({
    grid: [32,32],
    start: (event, ui) => {
      let destroyer = board.ships[1];
      obstacles = generateObstacles(destroyer, board);
      $destroyer.draggable("option", "multipleCollisionInteractions", obstacles);
      $destroyer.draggable("option", "revert", "invalid");
    }
  });

  $submarine.draggable({
    grid: [ 32,32 ],
    start: (event, ui) => {
      let submarine = board.ships[2];
      obstacles = generateObstacles(submarine, board);
      $submarine.draggable("option", "multipleCollisionInteractions", obstacles);
      $submarine.draggable("option", "revert", "invalid");
    }
  });

  $battleship.draggable({
    grid: [ 32,32 ],
    start: (event, ui) => {
      let battler = board.ships[3];
      obstacles = generateObstacles(battler, board);
      $battleship.draggable("option", "multipleCollisionInteractions", obstacles);
      $battleship.draggable("option", "revert", "invalid");
    }
  });

  $aircraft_carrier.draggable({
    grid: [ 32,32 ],
    start: (event, ui) => {
      let crafter = board.ships[4];
      obstacles = generateObstacles(crafter, board);
      $aircraft_carrier.draggable("option", "multipleCollisionInteractions", obstacles);
      $aircraft_carrier.draggable("option", "revert", "invalid");
    }
  });

  $('#board-setup').droppable({
    accept: ".ship",
    tolerance: "fit"
  });
});

$(document).ready(boardReady);
<|endoftext|>


<commit_before>(function(name, definition) {
    if (typeof module != 'undefined') module.exports = definition();
    else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
	else if (typeof jQuery === 'function') {
				// jQuery Plugin
            	return function(name,source) {
                	jQuery.fn[name] = source;
                	return;
            	};
    }
    else this[name] = definition();
}('Radiogram', function() {
  //normally have inside define() or add to module.exports
  //@Radiogram Global NAMESPACE
  var c,elm,len,str,ul,t=0,make__id=''; //@GLOBAL VARIABLES

  return {
			expose: function(selector,obj){
						   elm = document.querySelector(selector);
						   if(Radiogram.isObject(obj)){
						   		var lenObj = Object.keys(obj).length;
						   }
						   if((lenObj>0) && (lenObj<3)) rtn = Radiogram.analyzer(obj); //holding an array with values exported from object

			return true;
			},
			isObject :	function(obj){
						   //return true/false "TRUE" for object and else set to false
						return ((obj === null) || typeof obj == 'function') ? false :(typeof obj == 'object');
			},
			bindEvents: function(make__id){

						var parentWrapper = document.querySelector(make__id);
						var childWrapper='';

						for(c = 0; c < parentWrapper.children.length; c++){
        					childWrapper = parentWrapper.children[c];

										if (childWrapper.addEventListener) { // For all major browsers, except IE 8 and earlier
												childWrapper.addEventListener("click", Radiogram.eventHandler, false);
											}else if(childWrapper.attachEvent) { // IE Hacked For IE 8 and earlier versions
												childWrapper.attachEvent("onclick", Radiogram.eventHandler);
										}
									}//end of for-loop
							},
							eventHandler: function(e){
								//var clickedItem = e.target.lastChild;
								 var clickedItem = this.lastChild.id;
								 var radioname = this.lastChild.name; // purpose of

								 Radiogram.removeSection(radioname);
								 document.getElementById(clickedItem).setAttribute('checked', 'checked');

					},
					removeSection: function(radioname){
									var radioObj = document.getElementsByName(radioname);
								  	for(c=0;c< radioObj.length; c++ ){
										if (radioObj[c].checked) radioObj[c].removeAttribute('checked');
								  	}
					return true;
					},
					analyzer: function(obj) {
							  var objArray, attrName='';
							  for (var key in obj) {
							  if (obj.hasOwnProperty(key)) {
							  //alert(key + " -> " + obj[key]);
							  	if(key === "name") attrName = obj[key];
								else{
									str = obj[key].toString();
									objArray=str.split(",");
									}
							  }
							}

						return Radiogram.finalizer(attrName,objArray);
					},
					finalizer : function(attrName,chunk){
								str = '',i=0;
								t++; //tracker for multiple instance
								make__id = '#radiogroup' + t;
									ul 		= document.createElement("ul");

									ul.id 	= 'radiogroup' + t;

									ul.setAttribute("class","radiogram");

								var docfrag = document.createDocumentFragment();
								docfrag = docfrag.appendChild(ul);
								var li;
								for(c=0; c <chunk.length; c++){
									i++;
									li = document.createElement("li");
									str = chunk[c].toString() + '<input id="radio' + t + i + '" type="radio" name="' + attrName + '"/>';

									// this method adopted from native IE and accepted by other browsers
									// ref: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
									li.insertAdjacentHTML("beforeend", str);
								  	docfrag.appendChild(li);
								}

								elm.appendChild(docfrag);
								Radiogram.bindEvents(make__id);
								return true;

					}
    }
}));
<commit_msg>Update radiogram.js<commit_after>(function(name, definition) {
    if (typeof module != 'undefined') module.exports = definition();
    else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
	else if (typeof jQuery === 'function') {
				// jQuery Plugin
            	return function(name,source) {
                	jQuery.fn[name] = source;
                	return;
            	};
    }
    else this[name] = definition();
}('Radiogram', function() {
  //normally have inside define() or add to module.exports
  //@Radiogram Global NAMESPACE
  var c,elm,len,str,ul,t=0,make__id=''; //@GLOBAL VARIABLES

  return {
			expose: function(selector,obj){
				elm = document.querySelector(selector);
				if(Radiogram.isObject(obj)){
					var lenObj = Object.keys(obj).length;
				}
				if((lenObj>0) && (lenObj<3)) rtn = Radiogram.analyzer(obj); //holding an array with values exported from object

				return true;
				},
			isObject :function(obj){
				  //return true/false "TRUE" for object and else set to false
				  return ((obj === null) || typeof obj == 'function') ? false :(typeof obj == 'object');
				},
			bindEvents: function(make__id){

				var parentWrapper = document.querySelector(make__id);
				var childWrapper='';

				for(c = 0; c < parentWrapper.children.length; c++){
        			childWrapper = parentWrapper.children[c];

				if (childWrapper.addEventListener) { // For all major browsers, except IE 8 and earlier
					childWrapper.addEventListener("click", Radiogram.eventHandler, false);
					}else if(childWrapper.attachEvent) { // IE Hacked For IE 8 and earlier versions
						childWrapper.attachEvent("onclick", Radiogram.eventHandler);
					}
				   }//end of for-loop
				},
			eventHandler: function(e){
					var clickedItem = this.lastChild.id;
					var radioname = this.lastChild.name; // purpose of

					Radiogram.removeSection(radioname);
					document.getElementById(clickedItem).setAttribute('checked', 'checked');

					},
			removeSection: function(radioname){
					var radioObj = document.getElementsByName(radioname);
					for(c=0;c< radioObj.length; c++ ){
						if (radioObj[c].checked) radioObj[c].removeAttribute('checked');
						}
					return true;
					},
			analyzer: function(obj) {
					var objArray, attrName='';
					for (var key in obj) {
						if (obj.hasOwnProperty(key)) {
						if(key === "name") attrName = obj[key];
						else{
							str = obj[key].toString();
							objArray=str.split(",");
							}
						}
					}

					return Radiogram.finalizer(attrName,objArray);
					},
			finalizer : function(attrName,chunk){
					str = '',i=0;
					t++; //tracker for multiple instance
					make__id = '#radiogroup' + t;
					ul = document.createElement("ul");

					ul.id 	= 'radiogroup' + t;

					ul.setAttribute("class","radiogram");

					var docfrag = document.createDocumentFragment();
					docfrag = docfrag.appendChild(ul);
					var li;
					for(c=0; c <chunk.length; c++){
					i++;
					li = document.createElement("li");
					str = chunk[c].toString() + '<input id="radio' + t + i + '" type="radio" name="' + attrName + '"/>';

					// this method adopted from native IE and accepted by other browsers
					// ref: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
					li.insertAdjacentHTML("beforeend", str);
					docfrag.appendChild(li);
				}

				elm.appendChild(docfrag);
				Radiogram.bindEvents(make__id);
				return true;
			}
    	}
}));
<|endoftext|>


<commit_before>var
  config     = require('./config'),
  mocks      = require('./routes/mocks'),
  help       = require('./lib/routeHelpMessage'),
  components = require('./routes/components');

module.exports = function (app) {

  app.all('*', function(req, res, next){
    res.set('Access-Control-Allow-Origin', '*');
    res.set('Access-Control-Allow-Methods', 'GET');
    res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
    if ('OPTIONS' == req.method) return res.send(200);
    next();
  });

  app.get('/', function (req, res) {
    res.json(help);
  });

  app.get('/components', components.index);
  app.get('/components/:owner/:name', components.show);
  app.get('/components/:owner/:name/script.js', components.getScript);
  app.get('/components/:owner/:name/build.js', components.getBuild);

  app.use(function (err, req, res, next) {
    res.send(err.code || 500, { error: err.message });
  });

  if (config.isTest) {
    app.get('/mock/registry', mocks.registry);
  }
};
<commit_msg>Use mock registry route if using mocks, even in dev<commit_after>var
  config     = require('./config'),
  mocks      = require('./routes/mocks'),
  help       = require('./lib/routeHelpMessage'),
  components = require('./routes/components');

module.exports = function (app) {

  app.all('*', function(req, res, next){
    res.set('Access-Control-Allow-Origin', '*');
    res.set('Access-Control-Allow-Methods', 'GET');
    res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
    if ('OPTIONS' == req.method) return res.send(200);
    next();
  });

  app.get('/', function (req, res) {
    res.json(help);
  });

  app.get('/components', components.index);
  app.get('/components/:owner/:name', components.show);
  app.get('/components/:owner/:name/script.js', components.getScript);
  app.get('/components/:owner/:name/build.js', components.getBuild);

  app.use(function (err, req, res, next) {
    res.send(err.code || 500, { error: err.message });
  });

  if (config.useMocks) {
    app.get('/mock/registry', mocks.registry);
  }
};
<|endoftext|>


<commit_before>//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require fe/fe.common.js
//= require fe/jquery.scrollTo-min.js
//= require fe/jquery.validate.pack.js

// used by answer sheets

(function($) {
  //debugger;
	$(function() {

		$(document).on('click', '.save_button', function() {
			$.fe.pageHandler.savePage($(this).closest('.answer-page'), true);
		});

		$(document).on('click', '.reference_send_invite', function() {
            var el = this;
			var data = $(el).closest('form').serializeArray();

			data.push({name: 'answer_sheet_type', value: answer_sheet_type});
      $.ajax({url: $(el).attr('href'), data: data, dataType: 'script',  type: 'POST',
                        beforeSend: function (xhr) {
                            $('body').trigger('ajax:loading', xhr);
                        },
                        complete: function (xhr) {
                            $('body').trigger('ajax:complete', xhr);
                        },
                        error: function (xhr, status, error) {
                            $('body').trigger('ajax:failure', [xhr, status, error]);
                        }
										});
			return false;
		});
		$(document).on('focus', 'textarea[maxlength]', function() {
			var max = parseInt($(this).attr('maxlength'));
			$(this).parent().find('.charsRemaining').html('You have ' + (max - $(this).val().length) + ' characters remaining');
		}).on('keyup', 'textarea[maxlength]', function(){
			var max = parseInt($(this).attr('maxlength'));
			if($(this).val().length > max){
				$(this).val($(this).val().substr(0, $(this).attr('maxlength')));
			}
			$(this).parent().find('.charsRemaining').html('You have ' + (max - $(this).val().length) + ' characters remaining');
		}).on('blur', 'textarea[maxlength]', function() {
			$(this).parent().find('.charsRemaining').html('');
		});
  });

	$.fe = {};
	$.fe.pageHandler = {
	  initialize : function(page) {
	    this.auto_save_frequency = 30;  // seconds
	    this.timer_id = null;
		  this.suspendLoad = false;

	    this.current_page = page;
			$('#' + page).data('form_data', this.captureForm($('#' + page)));
	    this.registerAutoSave();

	    this.page_validation = {};  // validation objects for each page
	    this.enableValidation(page);

	    // this.background_load = false;
	    // this.final_submission = false;
	  },

	  // swap to a different page
	  showPage : function(page) {
	    // hide the old
	    $('#' + this.current_page + '-li').removeClass('active');
	    $('#' + this.current_page).hide();

			// HACK: Need to clear the main error message when returning to the submit page
			//       It is very confusing to users to be there when they revisit the page
			if ((page=='submit_page') && ($('#submit_message')[0] != null)) $('#submit_message').hide();
			if ((page=='submit_page') && ($('#application_errors')[0] != null)) $('#application_errors').html('');

	    // show the new
			// $('#' + page + '-li').removeClass('incomplete');
			// $('#' + page + '-li').removeClass('valid');
			$('#' + page + '-li').addClass('active');
	    $('#' + page).show();
	    this.current_page = page;
	    this.registerAutoSave(page);
	    this.suspendLoad = false;
	    fixGridColumnWidths();
	  },

	  // callback onSuccess
	  pageLoaded : function(response) {
	    // var response = new String(transport.responseText);
	    var match = response.match(/<div id=\"(.*?)\"/i); // what did I just load? parse out the first div id
	    if( match != null )
	    {
	      var page = match[1];
	      $('#preview').append(response);
	      // if(this.background_load) $('#' + page).hide(); else
				$.fe.pageHandler.showPage(page);  // show after load, unless loading in background
				setUpJsHelpers();
	      $.fe.pageHandler.enableValidation(page);
				// $.fe.pageHandler.validatePage('#' + page);
				$('#' + page).data('form_data', $.fe.pageHandler.captureForm($('#' + page)));
	    }
			$('#page_ajax_spinner').hide();
			$('.reference_send_invite').button();
			updateTotals();
			$(document).trigger('fePageLoaded'); // allow other code to handle page load event by using $(document).on('fePageLoaded', function() { ... });
	  },

	  loadPage : function(page, url) {
	    if (!this.suspendLoad) {
				this.suspendLoad = true; // don't load a page if one is currently loading (prevent double-click behavior where two pages end up visible!)

				this.unregisterAutoSave();  // don't auto-save while loading/saving
			      // will register auto-save on new page once loaded/shown

				$.scrollTo('#main');

		    this.validatePage(this.current_page);   // mark current page as valid (or not) as we're leaving

		    this.savePage();

		    if( $.fe.pageHandler.isPageLoaded(page) && page.match('no_cache') == null )   // if already loaded (element exists) excluding pages that need reloading
		    {
		      $.fe.pageHandler.showPage(page);
					$('#page_ajax_spinner').hide();
		    }
		    else
		    {
					$.ajax({
             url: url,
             type: 'GET',
						 data: {'answer_sheet_type':answer_sheet_type},
						 success: $.fe.pageHandler.pageLoaded,
             error: function (xhr, status, error) {
                alert("There was a problem loading that page. We've been notified and will fix it as soon as possible. To work on other pages, please refresh the website.");
								document.location = document.location;
             },
             beforeSend: function (xhr) {
                 $('body').trigger('ajax:loading', xhr);
             },
             complete: function (xhr) {
                 $('body').trigger('ajax:complete', xhr);
             }
         });
		      // new Ajax.Request(url, {asynchronous:true, evalScripts:false, method:'get',
		      //     onSuccess:this.pageLoaded.bind(this)});
		    }
			}
	  },

	  // save form if any changes were made
	  savePage : function(page, force) {
			if (page == null) page = $('#' + this.current_page);
      // don't save more than once per second
      timeNow = new Date();
      if (typeof(lastSave) != "undefined" && lastSave && !force && (timeNow - lastSave < 1000)) {
        return true;
      }
      lastSave = timeNow;
      form_data = this.captureForm(page);
      if( form_data ) {
        if( page.data('form_data') == null || page.data('form_data').data !== form_data.data || force === true) {  // if any changes
          page.data('form_data', form_data);
          $.ajax({url: form_data.url, type: 'put', data: form_data.data,
                 beforeSend: function (xhr) {
                   $('#spinner_' + page.attr('id')).show();
                 },
                 complete: function (xhr) {
                   $('#spinner_' + page.attr('id')).hide();
                 },
                 error: function() {
                   page.data('form_data', null);    // on error, force save for next call to save
                   // WARNING: race conditions with load & show?
                   // sort of a mess if save fails while another page is already loading!!
                 }});
        }
      }
      // Update last saved stamp
    },

		savePages : function(force) {
			$('.answer-page').each(function() {$.fe.pageHandler.savePage($(this), force)})
		},

	  // setup a timer to auto-save (only one timer, for the page being viewed)
	  registerAutoSave: function(page) {
	    this.timer_id = setInterval(this.savePages, this.auto_save_frequency * 1000);
	  },

	  unregisterAutoSave: function() {
	    if( this.timer_id != null )
	    {
	      clearInterval(this.timer_id);
	      this.timer_id = null;
	    }
	  },

	  // serialize form data and extract url to post to
	  captureForm : function(page) {
	    form_el = $('#' + page.attr('id') + '-form');
	    if( form_el[0] == null ) return null;
			return {url: form_el.attr('action'), data: form_el.serialize() + '&answer_sheet_type=' + answer_sheet_type};
	  },

	  // enable form validation (when form is loaded)
	  enableValidation : function(page) {
	    $('#' + page + '-form').validate({onsubmit:false, focusInvalid:true, onfocusout: function(element) { this.element(element);}});
	    // $('#' + page + '-form').valid();
	  },

	  validatePage : function(page) {
			try {
			  var li = $('#' + page + '-li');
			  var form = $('#' + page + '-form');

		    valid = form.valid();
				// Move radio button errors up
				$('input[type=radio].error').closest('tr').addClass('error');
				$('.choice_field input[type=radio].error').removeClass('error')
					.closest('.choice_field')
					.addClass('error');
				$('div.yesno label.error').hide();

		    if(valid)  {
		      el.removeClass('incomplete');
				  el.addClass('complete');
		    } else {
				  el.removeClass('complete');
		      el.addClass('incomplete');
		    }
		    return valid;
			}
			catch(err) {

				// If the user clicks too quickly, sometimes the page element isn't properly defined yet.
				// If we don't catch the error, js stops execution. If we catch it, the user just has to click again.
			}
			$('page_ajax_spinner').hide();
	  },

  // callback when falls to 0 active Ajax requests
  completeAll : function()
  {
		$('#submit_button').attr('disabled', true)
		$('#submit_message').html('');
		$('#submit_message').hide();
		// validate all the pages
  	$('.page_link').each(function(index, page) {
			$.fe.pageHandler.validatePage($(page).attr('data-page-id'));
		});
		var all_valid = ($('#list-pages li.incomplete').length == 0);

		// Make sure any necessary payments are made
		var payments_made = $('.payment_question.required').length <= $('.payment').length

		if(  payments_made)
		{
		  this.savePage($('#' + $.fe.pageHandler.current_page));  // in case any input fields on submit_page

		  // submit the application
		  if($('#submit_to')[0] != null)
		  {
		    url = $('#submit_to').val();
			  // clear out pages array to force reload.  This enables "frozen" apps
			  //       immediately after submission - :onSuccess (for USCM which stays in the application vs. redirecting to the dashboard)
			  var curr = $.fe.pageHandler.current_page;
			  $.ajax({url: url, dataType:'script',
			 		data: {answer_sheet_type: answer_sheet_type},
					type:'post',
					beforeSend: function(xhr) {
          	$('body').trigger('ajax:loading', xhr);
					},
					success: function(xhr) {
						$('#list-pages a').each(function() {
						  if ($(this).attr('data-page-id') != curr) $('#' + $(this).attr('data-page-id')).remove();
						})
					},
					complete: function(xhr) {
            $('body').trigger('ajax:complete', xhr);
		  			var btn = $('#submit_button');
						if (btn) { btn.attr('disabled', false); }
					}
				});
		  }
		}
		else
		{
		  // some pages aren't valid
 	    $('#submit_message').html("Please make a payment");
		  $('#submit_message').show();

		  var btn = $('#submit_button'); if (btn) { btn.attr('disabled', false); }
		}
  },

    // is page loaded? (useful for toggling enabled state of questions)
    isPageLoaded : function(page)
    {
      return $('#' + page)[0] != null
    },

    checkConditional : function($element_li) {
      matchable_answers = String($element_li.data('conditional_answer')).split(',').map(function(s) { return s.trim(); })
      if ($element_li.hasClass('fe_choicefield') && $element_li.hasClass('yes-no')) {
        if ($(matchable_answers).filter([1, '1', true, 'true', 'yes']).length > 0) {
          matchable_answers = [1, '1', true, 'true', 'yes'];
        }
        vals = $([$element_li.find("input[type=radio]:checked").val()]);
      } else if ($element_li.hasClass('fe_choicefield') && $element_li.hasClass('checkbox')) {
        vals = $element_li.find("input[type=checkbox]:checked").map(function(i, el) { return $(el).val(); });
      } else {
        vals = $([$element_li.find("input:visible, select:visible").val()]);
      }
      match = $(matchable_answers).filter(vals).length > 0;

      switch ($element_li.data('conditional_type')) {
        case 'Fe::Element':
          if (match) {
            $("#element_" + $element_li.data('conditional_id')).show();
          } else {
            $("#element_" + $element_li.data('conditional_id')).hide();
          }
        case 'Fe::Page':
          li_id = "li#fe_application_" + $element_li.data('application_id') + '-fe_page_' + $element_li.data('conditional_id') + '-li';
          if (match) {
            $(li_id).show();
          } else {
            $(li_id).hide();
          }
      }
    }

  };

  $(document).on('click', "li.conditional input, li.conditional select", function() {
    $.fe.pageHandler.checkConditional($(this).closest('li'));
  });
  $(document).on('keyup', "li.conditional input, li.conditional select", function() { $(this).click(); });
  $(document).on('blug', "li.conditional input, li.conditional select", function() { $(this).click(); });
  $(document).on('change', "li.conditional select", function() { $(this).click(); });

})(jQuery);

$(function() {
	fixGridColumnWidths();
  setUpCalendars();
});

function updateTotal(id) {
  try {
    total = 0;
    $(".col_" + id).each(function(index, el) {
      total += Number($(el).val());
    });
    $('#total_' + id).val(total).trigger('totalChanged');
  } catch(e) {
  }
}

function submitToFrame(id, url)
{
  form = $('<form method="post" action="'+url+'.js" endtype="multipart/form-data"></form>')
  var csrf_token = $('meta[name=csrf-token]').attr('content'),
      csrf_param = $('meta[name=csrf-param]').attr('content'),
			dom_id = '#attachment_field_' + id,
			metadata_input = '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />',
			file_field = '<input type="file" name="answers['+ id + ']>';
	if ($(dom_id).val() == '')	return;
  form.hide()
      .append(metadata_input)
      .append(file_field)
      .appendTo('body');
	$(dom_id + "-spinner").show();
  form.submit();
	return false
}
<commit_msg>el is never set up, use li as it is<commit_after>//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require fe/fe.common.js
//= require fe/jquery.scrollTo-min.js
//= require fe/jquery.validate.pack.js

// used by answer sheets

(function($) {
  //debugger;
	$(function() {

		$(document).on('click', '.save_button', function() {
			$.fe.pageHandler.savePage($(this).closest('.answer-page'), true);
		});

		$(document).on('click', '.reference_send_invite', function() {
            var el = this;
			var data = $(el).closest('form').serializeArray();

			data.push({name: 'answer_sheet_type', value: answer_sheet_type});
      $.ajax({url: $(el).attr('href'), data: data, dataType: 'script',  type: 'POST',
                        beforeSend: function (xhr) {
                            $('body').trigger('ajax:loading', xhr);
                        },
                        complete: function (xhr) {
                            $('body').trigger('ajax:complete', xhr);
                        },
                        error: function (xhr, status, error) {
                            $('body').trigger('ajax:failure', [xhr, status, error]);
                        }
										});
			return false;
		});
		$(document).on('focus', 'textarea[maxlength]', function() {
			var max = parseInt($(this).attr('maxlength'));
			$(this).parent().find('.charsRemaining').html('You have ' + (max - $(this).val().length) + ' characters remaining');
		}).on('keyup', 'textarea[maxlength]', function(){
			var max = parseInt($(this).attr('maxlength'));
			if($(this).val().length > max){
				$(this).val($(this).val().substr(0, $(this).attr('maxlength')));
			}
			$(this).parent().find('.charsRemaining').html('You have ' + (max - $(this).val().length) + ' characters remaining');
		}).on('blur', 'textarea[maxlength]', function() {
			$(this).parent().find('.charsRemaining').html('');
		});
  });

	$.fe = {};
	$.fe.pageHandler = {
	  initialize : function(page) {
	    this.auto_save_frequency = 30;  // seconds
	    this.timer_id = null;
		  this.suspendLoad = false;

	    this.current_page = page;
			$('#' + page).data('form_data', this.captureForm($('#' + page)));
	    this.registerAutoSave();

	    this.page_validation = {};  // validation objects for each page
	    this.enableValidation(page);

	    // this.background_load = false;
	    // this.final_submission = false;
	  },

	  // swap to a different page
	  showPage : function(page) {
	    // hide the old
	    $('#' + this.current_page + '-li').removeClass('active');
	    $('#' + this.current_page).hide();

			// HACK: Need to clear the main error message when returning to the submit page
			//       It is very confusing to users to be there when they revisit the page
			if ((page=='submit_page') && ($('#submit_message')[0] != null)) $('#submit_message').hide();
			if ((page=='submit_page') && ($('#application_errors')[0] != null)) $('#application_errors').html('');

	    // show the new
			// $('#' + page + '-li').removeClass('incomplete');
			// $('#' + page + '-li').removeClass('valid');
			$('#' + page + '-li').addClass('active');
	    $('#' + page).show();
	    this.current_page = page;
	    this.registerAutoSave(page);
	    this.suspendLoad = false;
	    fixGridColumnWidths();
	  },

	  // callback onSuccess
	  pageLoaded : function(response) {
	    // var response = new String(transport.responseText);
	    var match = response.match(/<div id=\"(.*?)\"/i); // what did I just load? parse out the first div id
	    if( match != null )
	    {
	      var page = match[1];
	      $('#preview').append(response);
	      // if(this.background_load) $('#' + page).hide(); else
				$.fe.pageHandler.showPage(page);  // show after load, unless loading in background
				setUpJsHelpers();
	      $.fe.pageHandler.enableValidation(page);
				// $.fe.pageHandler.validatePage('#' + page);
				$('#' + page).data('form_data', $.fe.pageHandler.captureForm($('#' + page)));
	    }
			$('#page_ajax_spinner').hide();
			$('.reference_send_invite').button();
			updateTotals();
			$(document).trigger('fePageLoaded'); // allow other code to handle page load event by using $(document).on('fePageLoaded', function() { ... });
	  },

	  loadPage : function(page, url) {
	    if (!this.suspendLoad) {
				this.suspendLoad = true; // don't load a page if one is currently loading (prevent double-click behavior where two pages end up visible!)

				this.unregisterAutoSave();  // don't auto-save while loading/saving
			      // will register auto-save on new page once loaded/shown

				$.scrollTo('#main');

		    this.validatePage(this.current_page);   // mark current page as valid (or not) as we're leaving

		    this.savePage();

		    if( $.fe.pageHandler.isPageLoaded(page) && page.match('no_cache') == null )   // if already loaded (element exists) excluding pages that need reloading
		    {
		      $.fe.pageHandler.showPage(page);
					$('#page_ajax_spinner').hide();
		    }
		    else
		    {
					$.ajax({
             url: url,
             type: 'GET',
						 data: {'answer_sheet_type':answer_sheet_type},
						 success: $.fe.pageHandler.pageLoaded,
             error: function (xhr, status, error) {
                alert("There was a problem loading that page. We've been notified and will fix it as soon as possible. To work on other pages, please refresh the website.");
								document.location = document.location;
             },
             beforeSend: function (xhr) {
                 $('body').trigger('ajax:loading', xhr);
             },
             complete: function (xhr) {
                 $('body').trigger('ajax:complete', xhr);
             }
         });
		      // new Ajax.Request(url, {asynchronous:true, evalScripts:false, method:'get',
		      //     onSuccess:this.pageLoaded.bind(this)});
		    }
			}
	  },

	  // save form if any changes were made
	  savePage : function(page, force) {
			if (page == null) page = $('#' + this.current_page);
      // don't save more than once per second
      timeNow = new Date();
      if (typeof(lastSave) != "undefined" && lastSave && !force && (timeNow - lastSave < 1000)) {
        return true;
      }
      lastSave = timeNow;
      form_data = this.captureForm(page);
      if( form_data ) {
        if( page.data('form_data') == null || page.data('form_data').data !== form_data.data || force === true) {  // if any changes
          page.data('form_data', form_data);
          $.ajax({url: form_data.url, type: 'put', data: form_data.data,
                 beforeSend: function (xhr) {
                   $('#spinner_' + page.attr('id')).show();
                 },
                 complete: function (xhr) {
                   $('#spinner_' + page.attr('id')).hide();
                 },
                 error: function() {
                   page.data('form_data', null);    // on error, force save for next call to save
                   // WARNING: race conditions with load & show?
                   // sort of a mess if save fails while another page is already loading!!
                 }});
        }
      }
      // Update last saved stamp
    },

		savePages : function(force) {
			$('.answer-page').each(function() {$.fe.pageHandler.savePage($(this), force)})
		},

	  // setup a timer to auto-save (only one timer, for the page being viewed)
	  registerAutoSave: function(page) {
	    this.timer_id = setInterval(this.savePages, this.auto_save_frequency * 1000);
	  },

	  unregisterAutoSave: function() {
	    if( this.timer_id != null )
	    {
	      clearInterval(this.timer_id);
	      this.timer_id = null;
	    }
	  },

	  // serialize form data and extract url to post to
	  captureForm : function(page) {
	    form_el = $('#' + page.attr('id') + '-form');
	    if( form_el[0] == null ) return null;
			return {url: form_el.attr('action'), data: form_el.serialize() + '&answer_sheet_type=' + answer_sheet_type};
	  },

	  // enable form validation (when form is loaded)
	  enableValidation : function(page) {
	    $('#' + page + '-form').validate({onsubmit:false, focusInvalid:true, onfocusout: function(element) { this.element(element);}});
	    // $('#' + page + '-form').valid();
	  },

	  validatePage : function(page) {
			try {
			  var li = $('#' + page + '-li');
			  var form = $('#' + page + '-form');

		    valid = form.valid();
				// Move radio button errors up
				$('input[type=radio].error').closest('tr').addClass('error');
				$('.choice_field input[type=radio].error').removeClass('error')
					.closest('.choice_field')
					.addClass('error');
				$('div.yesno label.error').hide();

		    if(valid)  {
		      li.removeClass('incomplete');
				  li.addClass('complete');
		    } else {
				  li.removeClass('complete');
		      li.addClass('incomplete');
		    }
		    return valid;
			}
			catch(err) {

				// If the user clicks too quickly, sometimes the page element isn't properly defined yet.
				// If we don't catch the error, js stops execution. If we catch it, the user just has to click again.
			}
			$('page_ajax_spinner').hide();
	  },

  // callback when falls to 0 active Ajax requests
  completeAll : function()
  {
		$('#submit_button').attr('disabled', true)
		$('#submit_message').html('');
		$('#submit_message').hide();
		// validate all the pages
  	$('.page_link').each(function(index, page) {
			$.fe.pageHandler.validatePage($(page).attr('data-page-id'));
		});
		var all_valid = ($('#list-pages li.incomplete').length == 0);

		// Make sure any necessary payments are made
		var payments_made = $('.payment_question.required').length <= $('.payment').length

		if(  payments_made)
		{
		  this.savePage($('#' + $.fe.pageHandler.current_page));  // in case any input fields on submit_page

		  // submit the application
		  if($('#submit_to')[0] != null)
		  {
		    url = $('#submit_to').val();
			  // clear out pages array to force reload.  This enables "frozen" apps
			  //       immediately after submission - :onSuccess (for USCM which stays in the application vs. redirecting to the dashboard)
			  var curr = $.fe.pageHandler.current_page;
			  $.ajax({url: url, dataType:'script',
			 		data: {answer_sheet_type: answer_sheet_type},
					type:'post',
					beforeSend: function(xhr) {
          	$('body').trigger('ajax:loading', xhr);
					},
					success: function(xhr) {
						$('#list-pages a').each(function() {
						  if ($(this).attr('data-page-id') != curr) $('#' + $(this).attr('data-page-id')).remove();
						})
					},
					complete: function(xhr) {
            $('body').trigger('ajax:complete', xhr);
		  			var btn = $('#submit_button');
						if (btn) { btn.attr('disabled', false); }
					}
				});
		  }
		}
		else
		{
		  // some pages aren't valid
 	    $('#submit_message').html("Please make a payment");
		  $('#submit_message').show();

		  var btn = $('#submit_button'); if (btn) { btn.attr('disabled', false); }
		}
  },

    // is page loaded? (useful for toggling enabled state of questions)
    isPageLoaded : function(page)
    {
      return $('#' + page)[0] != null
    },

    checkConditional : function($element_li) {
      matchable_answers = String($element_li.data('conditional_answer')).split(',').map(function(s) { return s.trim(); })
      if ($element_li.hasClass('fe_choicefield') && $element_li.hasClass('yes-no')) {
        if ($(matchable_answers).filter([1, '1', true, 'true', 'yes']).length > 0) {
          matchable_answers = [1, '1', true, 'true', 'yes'];
        }
        vals = $([$element_li.find("input[type=radio]:checked").val()]);
      } else if ($element_li.hasClass('fe_choicefield') && $element_li.hasClass('checkbox')) {
        vals = $element_li.find("input[type=checkbox]:checked").map(function(i, el) { return $(el).val(); });
      } else {
        vals = $([$element_li.find("input:visible, select:visible").val()]);
      }
      match = $(matchable_answers).filter(vals).length > 0;

      switch ($element_li.data('conditional_type')) {
        case 'Fe::Element':
          if (match) {
            $("#element_" + $element_li.data('conditional_id')).show();
          } else {
            $("#element_" + $element_li.data('conditional_id')).hide();
          }
        case 'Fe::Page':
          li_id = "li#fe_application_" + $element_li.data('application_id') + '-fe_page_' + $element_li.data('conditional_id') + '-li';
          if (match) {
            $(li_id).show();
          } else {
            $(li_id).hide();
          }
      }
    }

  };

  $(document).on('click', "li.conditional input, li.conditional select", function() {
    $.fe.pageHandler.checkConditional($(this).closest('li'));
  });
  $(document).on('keyup', "li.conditional input, li.conditional select", function() { $(this).click(); });
  $(document).on('blug', "li.conditional input, li.conditional select", function() { $(this).click(); });
  $(document).on('change', "li.conditional select", function() { $(this).click(); });

})(jQuery);

$(function() {
	fixGridColumnWidths();
  setUpCalendars();
});

function updateTotal(id) {
  try {
    total = 0;
    $(".col_" + id).each(function(index, el) {
      total += Number($(el).val());
    });
    $('#total_' + id).val(total).trigger('totalChanged');
  } catch(e) {
  }
}

function submitToFrame(id, url)
{
  form = $('<form method="post" action="'+url+'.js" endtype="multipart/form-data"></form>')
  var csrf_token = $('meta[name=csrf-token]').attr('content'),
      csrf_param = $('meta[name=csrf-param]').attr('content'),
			dom_id = '#attachment_field_' + id,
			metadata_input = '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />',
			file_field = '<input type="file" name="answers['+ id + ']>';
	if ($(dom_id).val() == '')	return;
  form.hide()
      .append(metadata_input)
      .append(file_field)
      .appendTo('body');
	$(dom_id + "-spinner").show();
  form.submit();
	return false
}
<|endoftext|>