<commit_before>
/*
 * This file is part of Invenio.
 * Copyright (C) 2013, 2014 CERN.
 *
 * Invenio is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * Invenio is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Invenio; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

define(function(require, exports, module) {
  'use strict';

  var $ = require('jquery'),
      tpl_file_entry = require('hgn!./templates/file_entry'),
      tpl_file_link = require('hgn!./templates/file_link'),
      tpl_flash_message = require('hgn!./templates/flash_message'),
      tpl_field_message = require('hgn!./templates/field_message');

  var PluploadWidget = function(element, options) {
    this.$element = $(element);
    this.options = $.extend({}, $.fn.pluploadWidget.defaults, options);

    this.init();
  };

  PluploadWidget.prototype = {

    constructor: PluploadWidget,

    init: function() {
    /*
     * Initialize plupload plugin for `element`.
     */

      var that = this,
          url = this.options.url,
          save_url = this.options.save_url,
          delete_url = this.options.delete_url,
          get_file_url = this.options.get_file_url,
          dropbox_url = this.options.dropbox_url,
          newdep_url = this.options.newdep_url,
          continue_url = this.options.continue_url;

      var $upload_start = this.$element.find('.upload-start'),
          $upload_stop = this.$element.find('.upload-stop'),
          $upload_speed = this.$element.find('.upload-speed'),
          $upload_filetable = this.$element.find('.upload-filetable'),
          $upload_filelist = this.$element.find('.upload-filelist');

      var had_error = false;

      this.uploader = new plupload.Uploader({
          // General settings
          runtimes : this.options.runtimes,
          url : url,
          max_file_size : this.options.max_file_size,
          chunk_size : this.options.chunk_size,
          unique_names : this.options.unique_names,
          browse_button : this.options.browse_button,
          drop_element : this.options.drop_element,
      });

      new plupload.QueueProgress();

      this.uploader.init();

      /**
       */

      function init_button_states(){
          $upload_start.addClass("disabled");
          $upload_stop.hide();
          $upload_start.show();
          $upload_speed.html('');
          had_error = false;
      }

      function redirect(){
          if(continue_url){
              if( window.location != continue_url ){
                  window.location = continue_url;
              }
          }
      }

      $upload_start.click(function(e) {
          e.preventDefault();

          $upload_start.addClass('disabled');
          $upload_start.hide();
          $upload_stop.show();

          if(that.uploader.files.length > 0){
              that.uploader.start();
          } else if (dropbox_files.length > 0) {
              start_dropbox_upload();
          }
      });

      $upload_stop.click(function(d){
          uploader.stop();
          $upload_stop.hide();
          $upload_start.show();
          $upload_start.removeClass('disabled');
          $.each(uploader.files, function(i, file) {
              if (file.loaded < file.size) {
                  $("#" + file.id + " .rmlink").show();
                  //$('#' + file.id + " .progress-bar").css('width', "0%");
              }
          });
          $upload_speed.html('');
          uploader.total.reset();
      });

      this.uploader.bind('FilesRemoved', function(up, files) {
          $.each(files, function(i, file) {
              $upload_filelist.find('#' + file.id).hide('fast', function(){
                  $upload_filelist.find('#' + file.id).remove();
                  if($upload_filelist.children().length === 0){
                      $upload_start.addClass("disabled");
                  }
              });
              if (file.status === plupload.DONE) { //If file has been successfully uploaded
                  $.ajax({
                      type: "POST",
                      url: delete_url,
                      data: $.param({
                          file_id: file.id
                      })
                  });
              }

          });
      });

      this.uploader.bind('UploadProgress', function(up, file) {
          $('#' + file.id + " .progress-bar").css('width', file.percent + "%");
          var upload_speed = that.getBytesWithUnit(up.total.bytesPerSec) + " per sec";
          console.log("Progress " + file.name + " - " + file.percent);
          $upload_speed.html(upload_speed);
          up.total.reset();
      });

      this.uploader.bind('UploadFile', function(up, file) {
          $('#' + file.id + " .rmlink").hide();
      });

      this.uploader.bind('FilesAdded', function(up, files) {
          var remove_files = [];
          $.each(up.files, function(i, file) {

          });

          that.$element.show();
          $upload_start.removeClass("disabled");
          $upload_filetable.show('slow');
          up.total.reset();
          var filename_already_exists = [];
          $.each(files, function(i, file) {
              // Check for existing file
              var removed = false;
              for(var j = 0; j<up.files.length; j++){
                  var existing_file = up.files[j];
                  if(existing_file.id != file.id && file.name == existing_file.name){
                      filename_already_exists.push(file.name);
                      up.removeFile(file);
                      removed = true;
                  }
              }
              if(!removed){
                  $upload_filelist.append(tpl_file_entry({
                          id: file.id,
                          filename: file.name,
                          filesize: that.getBytesWithUnit(file.size),
                          removeable: true,
                          progress: 0
                  }));
                  $('#' + file.id).show('fast');
                  $('#' + file.id + ' .rmlink').on("click", function(event){
                      up.removeFile(file);
                  });
              }
          });
          if(filename_already_exists.length > 0) {
              $upload_errors.hide();
              $upload_errors.append('
×Warning:' + filename_already_exists.join(", ") + " already exist.
");
              $upload_errors.show('fast');
          }
      });

      this.uploader.bind('FileUploaded', function(up, file, responseObj) {
          var res_data = {};

          try {
              res_data = JSON.parse(responseObj.response);
          } catch (err) {
              console.error(err);
          }

          file.server_id = res_data.id;

          $('#' + file.id + " .progress").removeClass("progress-striped");
          $('#' + file.id + " .progress-bar").css('width', "100%");
          $('#' + file.id + ' .rmlink').show();
          $('#' + file.id + " .progress").hide();
          $('#' + file.id + '_link').html(tpl_file_link({
              filename: file.name,
              download_url: get_file_url + "?file_id=" + res_data.id
          }));
          if (that.uploader.total.queued === 0)
              $upload_stop.hide();

          file.loaded = 0;
          $upload_speed.html('');
          up.total.reset();
      });

      function error_message(err) {
          var error_messages = {}, message, http_errors;

          error_messages[plupload.FILE_EXTENSION_ERROR] = "the file extensions is not allowed.";
          error_messages[plupload.FILE_SIZE_ERROR] = "the file is too big.";
          error_messages[plupload.GENERIC_ERROR] = "an unknown error.";
          error_messages[plupload.IO_ERROR] = "problems reading the file on disk.";
          error_messages[plupload.SECURITY_ERROR] = "problems reading the file on disk.";

          message = error_messages[err.code];

          if (message !== undefined) {
              return message;
          }

          if (err.code == plupload.HTTP_ERROR) {
              http_errors = {};
              http_errors[401] = "an authentication error. Please login first.";
              http_errors[403] = "lack of permissions.";
              http_errors[404] = "a server error.";
              http_errors[500] = "a server error.";

              message = http_errors[err.status];

              if (message !== undefined) {
                 return message;
              }
          }

          return "an unknown error occurred";
      }

      this.uploader.bind('Error', function(up, err) {
          had_error = true;
          var message = error_message(err);
          $upload_errors.hide();
          if (err.file){
              $('#' + err.file.id + " .progress").removeClass("progress-striped").addClass("progress-danger");
              $upload_errors.append(
                '
Error: Could not upload ' + err.file.name +" due to " + message + "
"
              );
          } else {
              $upload_errors.append(
                '
Error: ' + message + "
"
              );
          }
          $upload_errors.show('fast');
          $upload_start.addClass("disabled");
          $upload_stop.hide();
          $upload_start.show();
          up.refresh(); // Reposition Flash/Silverlight
      });

      this.uploader.bind('UploadComplete', function(up, files) {
        if(!had_error) {
          redirect();
        }
        init_button_states();
      });

      this.val(this.options.files);

      $upload_filelist.sortable({
          forcePlaceholderSize: true,
          forceHelperSizeType: true,
          handle: ".sortlink",
          start: function(event, ui) {
              $(ui.placeholder).show();
              $(ui.placeholder).html("				");
              $(ui.placeholder).css("visibility", "");
              var header_ths = $("#file-table thead th"),
                  item_tds = $(ui.helper).find("td"),
                  placeholder_tds = $(ui.placeholder).find("td");
              for(var i = 0; i < header_ths.length; i++){
                  $(item_tds[i]).width($(header_ths[i]).width());
                  $(placeholder_tds[i]).width($(header_ths[i]).width());
              }
          },
          update: function(event, ui){
              if (save_url) {
                  $(that.options.form_selector).trigger("dataSaveField", {
                    save_url: save_url,
                    name: "files",
                    value: that.val()
                  });
              }
          }
      });

      $upload_filelist.disableSelection();
    },

    getBytesWithUnit: function(bytes) {
      if( isNaN( bytes ) ){
            return '';
        }
      var units = [' bytes', ' KB', ' MB', ' GB'];
      var amountOf2s = Math.floor( Math.log( +bytes )/Math.log(2) );
      if( amountOf2s < 1 ){
        amountOf2s = 0;
      }
      var i = Math.floor( amountOf2s / 10 );
      bytes = +bytes / Math.pow( 2, 10*i );

      // Rounds to 2 decimals places.
        var bytes_to_fixed = bytes.toFixed(2);
        if( bytes.toString().length > bytes_to_fixed.toString().length ){
            bytes = bytes_to_fixed;
        }
      return bytes + units[i];
    },

    fake_file: function (file) {
      var plfile = new plupload.File({
          id: file.id,
          name: file.name,
          size: file.size
      });
      // Dont touch it!
      // For some reason the constructor doesn't initialize
      // the data members
      plfile.id = file.id;
      plfile.server_id = file.server_id || file.id;
      plfile.name = file.name;
      plfile.size = file.size;
      // loaded is set to 0 as a temporary fix plupload's bug in
      // calculating current upload speed. For checking if a file
      // has been uploaded, check file.status
      plfile.loaded = 0; //file.size;
      plfile.status = 5; //status = plupload.DONE
      plfile.percent = 100;
      return plfile;
    },

    val: function (value) {
      /* Set/get list of files from Plupload. */
      var that = this, ids, files, result,
          $upload_filetable = this.$element.find('.upload-filetable'),
          $upload_filelist = this.$element.find('.upload-filelist');

      if ( arguments.length ) {
          if (!$.isEmptyObject(value)) {
              $upload_filetable.show('slow');

              $.each(value, function(i, file) {
                  // Simulate a plupload file object
                  var plfile = that.fake_file(file);

                  that.uploader.files.push(plfile);
                  $upload_filelist.append(tpl_file_entry({
                      id: plfile.id,
                      filename: plfile.name,
                      filesize: that.getBytesWithUnit(plfile.size),
                      download_url: that.options.get_file_url + "?file_id=" + plfile.id,
                      removeable: true,
                      completed: true,
                  }));
                  $('#' + plfile.id).show('fast');
                  $("#" + plfile.id + " .rmlink").on("click", function(event) {
                      that.uploader.removeFile(plfile);
                  });
              });
          }

        return;
      }
      // Extract ids
      ids = this.$element.find('tr[id]').map(function(){ return $(this).attr('id');});
      // Build search dict
      files = {};
      $.each(this.uploader.files, function(idx, elem){
          files[elem.id] = elem;
      });
      // Build ordered list of server ids.
      result = [];
      $.each(ids, function(idx, id){
          var file = files[id];
          if(file !== undefined && file.status == 5) {
              result.push(file.server_id);
          }
      });
      return result;
    },

    connectEvents: function() {},

    onStart: function() {},

    onStop: function() {},

  };

  $.fn.pluploadWidget = function ( option ) {
    return this.each(function () {
      var $this = $(this),
          data = $this.data('pluploadWidget'),
          options = typeof option == 'object' && option;
      if (!data) {
        $this.data('pluploadWidget', (data = new PluploadWidget(this, options)));
      }
      if (typeof option == 'string') {
        data[option]();
      }
    });
  };

  $.fn.pluploadWidget.defaults = {
    files: null,
    runtimes: 'html5',
    chunksize: '10mb',
    unique_names : true,
    browse_button : 'pickfiles',
    drop_element : 'field-plupload_file',
    form_selector: "#submitForm"
  };

  $.fn.pluploadWidget.Constructor = PluploadWidget;

});
<commit_msg>deposit: plupload filter option addition<commit_after>
/*
 * This file is part of Invenio.
 * Copyright (C) 2013, 2014 CERN.
 *
 * Invenio is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * Invenio is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Invenio; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

define(function(require, exports, module) {
  'use strict';

  var $ = require('jquery'),
      tpl_file_entry = require('hgn!./templates/file_entry'),
      tpl_file_link = require('hgn!./templates/file_link'),
      tpl_flash_message = require('hgn!./templates/flash_message'),
      tpl_field_message = require('hgn!./templates/field_message');

  var PluploadWidget = function(element, options) {
    this.$element = $(element);
    this.options = $.extend({}, $.fn.pluploadWidget.defaults, options);

    this.init();
  };

  PluploadWidget.prototype = {

    constructor: PluploadWidget,

    init: function() {
    /*
     * Initialize plupload plugin for `element`.
     */

      var that = this,
          url = this.options.url,
          save_url = this.options.save_url,
          delete_url = this.options.delete_url,
          get_file_url = this.options.get_file_url,
          dropbox_url = this.options.dropbox_url,
          newdep_url = this.options.newdep_url,
          continue_url = this.options.continue_url;

      var $upload_start = this.$element.find('.upload-start'),
          $upload_stop = this.$element.find('.upload-stop'),
          $upload_speed = this.$element.find('.upload-speed'),
          $upload_filetable = this.$element.find('.upload-filetable'),
          $upload_filelist = this.$element.find('.upload-filelist');

      var had_error = false;

      this.uploader = new plupload.Uploader({
          // General settings
          runtimes : this.options.runtimes,
          url : url,
          max_file_size : this.options.max_file_size,
          chunk_size : this.options.chunk_size,
          unique_names : this.options.unique_names,
          browse_button : this.options.browse_button,
          drop_element : this.options.drop_element,
          filters : this.options.filters,
      });

      new plupload.QueueProgress();

      this.uploader.init();

      /**
       */

      function init_button_states(){
          $upload_start.addClass("disabled");
          $upload_stop.hide();
          $upload_start.show();
          $upload_speed.html('');
          had_error = false;
      }

      function redirect(){
          if(continue_url){
              if( window.location != continue_url ){
                  window.location = continue_url;
              }
          }
      }

      $upload_start.click(function(e) {
          e.preventDefault();

          $upload_start.addClass('disabled');
          $upload_start.hide();
          $upload_stop.show();

          if(that.uploader.files.length > 0){
              that.uploader.start();
          } else if (dropbox_files.length > 0) {
              start_dropbox_upload();
          }
      });

      $upload_stop.click(function(d){
          uploader.stop();
          $upload_stop.hide();
          $upload_start.show();
          $upload_start.removeClass('disabled');
          $.each(uploader.files, function(i, file) {
              if (file.loaded < file.size) {
                  $("#" + file.id + " .rmlink").show();
                  //$('#' + file.id + " .progress-bar").css('width', "0%");
              }
          });
          $upload_speed.html('');
          uploader.total.reset();
      });

      this.uploader.bind('FilesRemoved', function(up, files) {
          $.each(files, function(i, file) {
              $upload_filelist.find('#' + file.id).hide('fast', function(){
                  $upload_filelist.find('#' + file.id).remove();
                  if($upload_filelist.children().length === 0){
                      $upload_start.addClass("disabled");
                  }
              });
              if (file.status === plupload.DONE) { //If file has been successfully uploaded
                  $.ajax({
                      type: "POST",
                      url: delete_url,
                      data: $.param({
                          file_id: file.id
                      })
                  });
              }

          });
      });

      this.uploader.bind('UploadProgress', function(up, file) {
          $('#' + file.id + " .progress-bar").css('width', file.percent + "%");
          var upload_speed = that.getBytesWithUnit(up.total.bytesPerSec) + " per sec";
          console.log("Progress " + file.name + " - " + file.percent);
          $upload_speed.html(upload_speed);
          up.total.reset();
      });

      this.uploader.bind('UploadFile', function(up, file) {
          $('#' + file.id + " .rmlink").hide();
      });

      this.uploader.bind('FilesAdded', function(up, files) {
          var remove_files = [];
          $.each(up.files, function(i, file) {

          });

          that.$element.show();
          $upload_start.removeClass("disabled");
          $upload_filetable.show('slow');
          up.total.reset();
          var filename_already_exists = [];
          $.each(files, function(i, file) {
              // Check for existing file
              var removed = false;
              for(var j = 0; j<up.files.length; j++){
                  var existing_file = up.files[j];
                  if(existing_file.id != file.id && file.name == existing_file.name){
                      filename_already_exists.push(file.name);
                      up.removeFile(file);
                      removed = true;
                  }
              }
              if(!removed){
                  $upload_filelist.append(tpl_file_entry({
                          id: file.id,
                          filename: file.name,
                          filesize: that.getBytesWithUnit(file.size),
                          removeable: true,
                          progress: 0
                  }));
                  $('#' + file.id).show('fast');
                  $('#' + file.id + ' .rmlink').on("click", function(event){
                      up.removeFile(file);
                  });
              }
          });
          if(filename_already_exists.length > 0) {
              $upload_errors.hide();
              $upload_errors.append('
×Warning:' + filename_already_exists.join(", ") + " already exist.
");
              $upload_errors.show('fast');
          }
      });

      this.uploader.bind('FileUploaded', function(up, file, responseObj) {
          var res_data = {};

          try {
              res_data = JSON.parse(responseObj.response);
          } catch (err) {
              console.error(err);
          }

          file.server_id = res_data.id;

          $('#' + file.id + " .progress").removeClass("progress-striped");
          $('#' + file.id + " .progress-bar").css('width', "100%");
          $('#' + file.id + ' .rmlink').show();
          $('#' + file.id + " .progress").hide();
          $('#' + file.id + '_link').html(tpl_file_link({
              filename: file.name,
              download_url: get_file_url + "?file_id=" + res_data.id
          }));
          if (that.uploader.total.queued === 0)
              $upload_stop.hide();

          file.loaded = 0;
          $upload_speed.html('');
          up.total.reset();
      });

      function error_message(err) {
          var error_messages = {}, message, http_errors;

          error_messages[plupload.FILE_EXTENSION_ERROR] = "the file extensions is not allowed.";
          error_messages[plupload.FILE_SIZE_ERROR] = "the file is too big.";
          error_messages[plupload.GENERIC_ERROR] = "an unknown error.";
          error_messages[plupload.IO_ERROR] = "problems reading the file on disk.";
          error_messages[plupload.SECURITY_ERROR] = "problems reading the file on disk.";

          message = error_messages[err.code];

          if (message !== undefined) {
              return message;
          }

          if (err.code == plupload.HTTP_ERROR) {
              http_errors = {};
              http_errors[401] = "an authentication error. Please login first.";
              http_errors[403] = "lack of permissions.";
              http_errors[404] = "a server error.";
              http_errors[500] = "a server error.";

              message = http_errors[err.status];

              if (message !== undefined) {
                 return message;
              }
          }

          return "an unknown error occurred";
      }

      this.uploader.bind('Error', function(up, err) {
          had_error = true;
          var message = error_message(err);
          $upload_errors.hide();
          if (err.file){
              $('#' + err.file.id + " .progress").removeClass("progress-striped").addClass("progress-danger");
              $upload_errors.append(
                '
Error: Could not upload ' + err.file.name +" due to " + message + "
"
              );
          } else {
              $upload_errors.append(
                '
Error: ' + message + "
"
              );
          }
          $upload_errors.show('fast');
          $upload_start.addClass("disabled");
          $upload_stop.hide();
          $upload_start.show();
          up.refresh(); // Reposition Flash/Silverlight
      });

      this.uploader.bind('UploadComplete', function(up, files) {
        if(!had_error) {
          redirect();
        }
        init_button_states();
      });

      this.val(this.options.files);

      $upload_filelist.sortable({
          forcePlaceholderSize: true,
          forceHelperSizeType: true,
          handle: ".sortlink",
          start: function(event, ui) {
              $(ui.placeholder).show();
              $(ui.placeholder).html("				");
              $(ui.placeholder).css("visibility", "");
              var header_ths = $("#file-table thead th"),
                  item_tds = $(ui.helper).find("td"),
                  placeholder_tds = $(ui.placeholder).find("td");
              for(var i = 0; i < header_ths.length; i++){
                  $(item_tds[i]).width($(header_ths[i]).width());
                  $(placeholder_tds[i]).width($(header_ths[i]).width());
              }
          },
          update: function(event, ui){
              if (save_url) {
                  $(that.options.form_selector).trigger("dataSaveField", {
                    save_url: save_url,
                    name: "files",
                    value: that.val()
                  });
              }
          }
      });

      $upload_filelist.disableSelection();
    },

    getBytesWithUnit: function(bytes) {
      if( isNaN( bytes ) ){
            return '';
        }
      var units = [' bytes', ' KB', ' MB', ' GB'];
      var amountOf2s = Math.floor( Math.log( +bytes )/Math.log(2) );
      if( amountOf2s < 1 ){
        amountOf2s = 0;
      }
      var i = Math.floor( amountOf2s / 10 );
      bytes = +bytes / Math.pow( 2, 10*i );

      // Rounds to 2 decimals places.
        var bytes_to_fixed = bytes.toFixed(2);
        if( bytes.toString().length > bytes_to_fixed.toString().length ){
            bytes = bytes_to_fixed;
        }
      return bytes + units[i];
    },

    fake_file: function (file) {
      var plfile = new plupload.File({
          id: file.id,
          name: file.name,
          size: file.size
      });
      // Dont touch it!
      // For some reason the constructor doesn't initialize
      // the data members
      plfile.id = file.id;
      plfile.server_id = file.server_id || file.id;
      plfile.name = file.name;
      plfile.size = file.size;
      // loaded is set to 0 as a temporary fix plupload's bug in
      // calculating current upload speed. For checking if a file
      // has been uploaded, check file.status
      plfile.loaded = 0; //file.size;
      plfile.status = 5; //status = plupload.DONE
      plfile.percent = 100;
      return plfile;
    },

    val: function (value) {
      /* Set/get list of files from Plupload. */
      var that = this, ids, files, result,
          $upload_filetable = this.$element.find('.upload-filetable'),
          $upload_filelist = this.$element.find('.upload-filelist');

      if ( arguments.length ) {
          if (!$.isEmptyObject(value)) {
              $upload_filetable.show('slow');

              $.each(value, function(i, file) {
                  // Simulate a plupload file object
                  var plfile = that.fake_file(file);

                  that.uploader.files.push(plfile);
                  $upload_filelist.append(tpl_file_entry({
                      id: plfile.id,
                      filename: plfile.name,
                      filesize: that.getBytesWithUnit(plfile.size),
                      download_url: that.options.get_file_url + "?file_id=" + plfile.id,
                      removeable: true,
                      completed: true,
                  }));
                  $('#' + plfile.id).show('fast');
                  $("#" + plfile.id + " .rmlink").on("click", function(event) {
                      that.uploader.removeFile(plfile);
                  });
              });
          }

        return;
      }
      // Extract ids
      ids = this.$element.find('tr[id]').map(function(){ return $(this).attr('id');});
      // Build search dict
      files = {};
      $.each(this.uploader.files, function(idx, elem){
          files[elem.id] = elem;
      });
      // Build ordered list of server ids.
      result = [];
      $.each(ids, function(idx, id){
          var file = files[id];
          if(file !== undefined && file.status == 5) {
              result.push(file.server_id);
          }
      });
      return result;
    },

    connectEvents: function() {},

    onStart: function() {},

    onStop: function() {},

  };

  $.fn.pluploadWidget = function ( option ) {
    return this.each(function () {
      var $this = $(this),
          data = $this.data('pluploadWidget'),
          options = typeof option == 'object' && option;
      if (!data) {
        $this.data('pluploadWidget', (data = new PluploadWidget(this, options)));
      }
      if (typeof option == 'string') {
        data[option]();
      }
    });
  };

  $.fn.pluploadWidget.defaults = {
    files: null,
    runtimes: 'html5',
    chunksize: '10mb',
    unique_names : true,
    browse_button : 'pickfiles',
    drop_element : 'field-plupload_file',
    form_selector: "#submitForm",
    filters : {}
  };

  $.fn.pluploadWidget.Constructor = PluploadWidget;

});
<|endoftext|>


<commit_before>// Framework for the cool UI tricks

// Set up a safe, global namespace in the jQuery object.
$.riakControl = $.riakControl || {};

$(function() {

    /* ALLOWS YOU TO HIT ENTER IN THE ADD-NODE FIELD WITHOUT MAKING IT A FORM */
    $(document).on('keyup', '#node-to-add', function (event) {
        if(event.keyCode === 13){
            $('#add-node-button').trigger('click');
        }
    });

    /* MAKE ALL CLOSE ERROR BUTTONS WORK */
    $(document).on('click', '.close-error', function () {
        $(this).parent().hide();
    });

    /* ENABLE THE SPLIT BAR */
    var splitBar = $('#split-bar');
    var splitBarParent = splitBar.parent();
    splitBar.css('height', splitBarParent.css('height'));

    /* If you need to resize the split bar when the window resizes
    var timer;
    $(window).resize(function(){
        clearTimeout(timer);
        timer = setTimeout(function(){
            var newHeight = splitBarParent.css('height');
            console.log(newHeight);
        }, 100);
    });
    */
    /* TURN ON TOGGLING FOR THE SPLIT BAR */
    splitBar.on('click', function () {
        var nav = $('#navigation'), navwidth = nav.css('width');
        var navbox = $('#nav-box'), boxwidth = navbox.css('width');
        if (navwidth === '218px') {
            nav.animate({"width":"54px"},{queue:false,duration:200});
            navbox.animate({"width":"62px"},{queue:false,duration:200});
        } else {
            nav.animate({"width":"218px"},{queue:false,duration:200});
            navbox.animate({"width":"226px"},{queue:false,duration:200});
        }
    });

    /* HANDLE ACTIVE INDICATOR ANIMATION */
    $('.nav-li').on('click', function () {
        var me = $(this), indicator = $('#active-nav');
        indicator.animate({"top":me.position().top},{queue:false,duration:200});
    });

    /*
    MAKE ON/OFF SWITCHES WORK
    To set up: each div.gui-switch should contain two radio buttons.  One with an
    'off' value and one with an 'on' value.  Whichever is checked should be controlled
    by whether the node is actually on or off.
    */
    // Define a re-usable function to use any time a new node is created.
    // If the node is on or off, set switch class accordingly.
    function setGuiSwitch (i, e) {
        var me = $(e),
            isOn = (me.find('input[checked=checked]').attr('value').toLowerCase() === 'on');
        if (isOn) {
            me.removeClass('off').addClass('on');
        } else {
            me.removeClass('on').addClass('off');
        }
    }
    // When the document is ready, run setGuiSwitch on all on/off switches
    $('.gui-switch').each(setGuiSwitch);
    // When a switch changes, alter its class accordingly.
    $('.gui-switch input').on('change', function(e) {
        var that = $(this),
            theValue = that.attr('value').toLowerCase(),
            isChecked = (that.attr('checked') === 'checked'),
            theParent = that.closest('.gui-switch');
        if (theValue === 'on') {
            theParent.removeClass('off').addClass('on');
        } else if (theValue === 'off') {
            theParent.removeClass('on').addClass('off');
        }
    });
    // END CODE FOR ON/OFF SWITCHES

    /* MAKE CHECKBOXES WORK WHEN YOU CLICK THEM */
    $(document).on('change', '.gui-checkbox', function(e) {
        var me = $(this), parent = me.parent(); checked = me.attr('checked');
        if (checked) {
            parent.css('background-position', 'left top');
        } else {
            parent.css('background-position', 'left bottom');
        }
    });

    /* CODE FOR ALL THE TOOLTIPS */
    var wait;
    function emptyTips () {
        wait = setTimeout(function () {
            $('#tooltips').slideUp(function() {
                $('#display-tips').empty();
            });
        }, 500);
    }
    function displayTips (str) {
        var disp = $('#tooltips').css('display');
        if (disp === 'none') {
            $('#tooltips').slideDown();
        }
        $('#display-tips').html(str);
        clearTimeout(wait);
    }

    // Navigation

    // Basho Logo
    $(document).on('mouseover', '#basho-logo', function () {
        displayTips('Riak and Riak Control are products of Basho Technologies.  Visit our website to learn more.');
    }).on('mouseout', '#basho-logo', emptyTips);

    // Cluster link in navigation
    $(document).on('mouseover', '#nav-cluster', function () {
        displayTips('The cluster view allows you to add and remove nodes from your cluster as well as stop Riak on various nodes or mark them as down.  You will also be able to view percentages indicating how much ring data is owned by each node.');
    }).on('mouseout', '#nav-cluster', emptyTips);

    // Ring link in navigation
    $(document).on('mouseover', '#nav-ring', function () {
        displayTips('The ring view shows a list of your partitions indicating which node owns each partition.  You have the ability to apply filters to your view of the partitions and see indicators showing the status of various node workers, whether they are in active, fallback, or handoff states.');
    }).on('mouseout', '#nav-ring', emptyTips);

    // Snapshot link in navigation
    $(document).on('mouseover', '#nav-snapshot', function () {
        displayTips('Selecting the snapshot view commands Riak Control to gather some general information related to the current health of your cluster.  It is useful in quickly determining whether or not there are any issues to be concerned about.');
    }).on('mouseout', '#nav-snapshot', emptyTips);

    // Cluster View

    // Add new node area
    $(document).on('mouseover', '#add-node table', function () {
        displayTips('Type a node name (for example: dev2@127.0.0.1) into the text field and hit "Add Node" to add it to this cluster.  The node will then take ownership of partitions in the ring to help ensure balanced data across the cluster.');
    }).on('mouseout', '#add-node table', emptyTips);

    // Name of a node
    $(document).on('mouseover', '.node .name', function () {
        var name = $(this).text();
        displayTips('This node is named ' + name + '.  It is a member of this cluster.');
    }).on('mouseout', '.node .name', emptyTips);

    // View actions cluster sliders
    $(document).on('mouseover', '.more-actions-slider-box .gui-slider', function () {
        displayTips('Move the slider over to view possible actions for this node.  Move the slider back to hide those actions again.');
    }).on('mouseout', '.more-actions-slider-box .gui-slider', emptyTips);

    // Leave cluster button
    $(document).on('mouseover', '.leave-cluster-button', function () {
        displayTips('This will cause the node to begin relinquishing ownership of its data to other nodes in the cluster.  You will not be able to interact with the node via Riak Control during this process.  Once completed, Riak will shutdown on this node and it will leave the cluster.');
    }).on('mouseout', '.leave-cluster-button', emptyTips);

    // The 'Hosting Riak Control' message
    $(document).on('mouseover', '.current-host', function () {
        displayTips('This node cannot be shutdown or removed via Riak Control because it is currently hosting the app.');
    }).on('mouseout', '.current-host', emptyTips);

    // Markdown button
    $(document).on('mouseover', '.markdown-button', function () {
        displayTips('This button becomes active when the node becomes unreachable.  While in an unreachable state, a node may hinder cluster membership changes of other nodes.  Marking this node as "down" will allow other nodes to engage in membership changes unimpeded.');
    }).on('mouseout', '.markdown-button', emptyTips);

    // Shutdown button
    $(document).on('mouseover', '.shutdown-button', function () {
        displayTips('This button will stop the Riak process on this node.  If this button is not active, your node is already unreachable.  It will have to be restarted manually.');
    }).on('mouseout', '.shutdown-button', emptyTips);

    // Ring ownership percent
    $(document).on('mouseover', '.ring_pct', function () {
        displayTips('The portion of the ring owned by this node.');
    }).on('mouseout', '.ring_pct', emptyTips);

    // Ring pending ownership percent
    $(document).on('mouseover', '.pending_pct', function () {
        displayTips('This is the desired portion of the ring this node should own.  As long as "% Owned" does not equal "% Pending," it means that this node is either in the process of receiving partition data from other nodes or handing some (or all) of its data off to other nodes.');
    }).on('mouseout', '.pending_pct', emptyTips);

    // Memory usage
    $(document).on('mouseover', '.membar-bg, .free-memory', function () {
        var parent = $(this).parent(),
            free_mem = parent.find('.free-memory').text(),
            erlang_mem, non_erlang_mem;
        if (free_mem.charAt(0) === '?') {
            displayTips('Because this node is currently unreachable, Riak Control is not able to assess its memory usage.');
        } else {
            free_mem = parseInt(free_mem);
            erlang_mem = parseInt(parent.find('.erlang-mem').attr('name'));
            non_erlang_mem = parseInt(parent.find('.non-erlang-mem').attr('name'));
            displayTips('The machine running this node currently has ' + free_mem + '% free memory.  Of the ' + (erlang_mem + non_erlang_mem) + '% currently in use, ' + erlang_mem + '% is being used by Riak and ' + non_erlang_mem + '% is being used by other processes.');
        }
    }).on('mouseout', '.membar-bg, .free-memory', emptyTips);

    // Node status
    $(document).on('mouseover', '.status-box', function () {
        var mytext = $(this).find('.status').text().toLowerCase();
        if (mytext === 'valid') {
            displayTips('This node is currently online and working.');
        } else if (mytext === 'unreachable') {
            displayTips('This node is unreachable.  Riak may need to be restarted or there may be other connectivity issues.  Cluster membership changes like "join" and "leave" cannot complete until this node is reachable or marked as "down".');
        } else if (mytext === 'down') {
            displayTips('This node has been marked as "down". While in this state it can not be interacted with but it will not impede cluster membership changes of other nodes.  To return to a "valid" state, simply restart Riak on this node.');
        } else if (mytext === 'leaving') {
            displayTips('This node is in process of leaving the cluster.  When it has finished relinquishing ownership and transferring data to other nodes, Riak will stop on this node and it will cease to be a member of the cluster.  You can not interact with this node during this process.');
        }
    }).on('mouseout', '.status-box', emptyTips);

    // Ring View

    // Ring filter
    $(document).on('mouseover', '#ring-filter', function () {
        displayTips('Select a node from the dropdown to view only the partitions owned by that node.  If you uncheck the boxes next to "Primary" or "Fallback", partitions in primary or fallback states will be removed from the view.');
    }).on('mouseout', '#ring-filter', emptyTips);

    // Partition owner
    $(document).on('mouseover', '.owner', function () {
        var partitionIndex = $(this).next().text();
        displayTips('The name of the node that owns this partition. (Partition Index: ' + partitionIndex + ')');
    }).on('mouseout', '.owner', emptyTips);

    // Worker Lights
    $(document).on('mouseover', '.kv-light, .pipe-light, .search-light', function () {
        var that = $(this);
        var texts;

        if (that.hasClass('kv-light')) {
            texts = {"status": that.find('.kv-status').text().toLowerCase(), "msg" : "Key-Value Store: "};
        } else if (that.hasClass('pipe-light')) {
            texts = {"status": that.find('.pipe-status').text().toLowerCase(), "msg" : "Pipeline Queue Process: "};
        } else if (that.hasClass('search-light')) {
            texts = {"status": that.find('.search-status').text().toLowerCase(), "msg" : "Riak Search: "};
        }

        if (texts.status === 'active') {
            displayTips(texts.msg + 'This node worker is active and ready.');
        } else if (texts.status === 'fallback') {
            displayTips(texts.msg + 'This node worker is not currently active.  This may be because its owner node is down or unreachable.  Operations normally handled by this node are currently in fallback to another node.');
        } else if (texts.status === 'handoff') {
            displayTips(texts.msg + 'This node worker is currently in the process of handing off its data to other nodes.');
        }
    }).on('mouseout', '.kv-light, .pipe-light, .search-light', emptyTips);

});<commit_msg>Updated a tooltip<commit_after>// Framework for the cool UI tricks

// Set up a safe, global namespace in the jQuery object.
$.riakControl = $.riakControl || {};

$(function() {

    /* ALLOWS YOU TO HIT ENTER IN THE ADD-NODE FIELD WITHOUT MAKING IT A FORM */
    $(document).on('keyup', '#node-to-add', function (event) {
        if(event.keyCode === 13){
            $('#add-node-button').trigger('click');
        }
    });

    /* MAKE ALL CLOSE ERROR BUTTONS WORK */
    $(document).on('click', '.close-error', function () {
        $(this).parent().hide();
    });

    /* ENABLE THE SPLIT BAR */
    var splitBar = $('#split-bar');
    var splitBarParent = splitBar.parent();
    splitBar.css('height', splitBarParent.css('height'));

    /* If you need to resize the split bar when the window resizes
    var timer;
    $(window).resize(function(){
        clearTimeout(timer);
        timer = setTimeout(function(){
            var newHeight = splitBarParent.css('height');
            console.log(newHeight);
        }, 100);
    });
    */
    /* TURN ON TOGGLING FOR THE SPLIT BAR */
    splitBar.on('click', function () {
        var nav = $('#navigation'), navwidth = nav.css('width');
        var navbox = $('#nav-box'), boxwidth = navbox.css('width');
        if (navwidth === '218px') {
            nav.animate({"width":"54px"},{queue:false,duration:200});
            navbox.animate({"width":"62px"},{queue:false,duration:200});
        } else {
            nav.animate({"width":"218px"},{queue:false,duration:200});
            navbox.animate({"width":"226px"},{queue:false,duration:200});
        }
    });

    /* HANDLE ACTIVE INDICATOR ANIMATION */
    $('.nav-li').on('click', function () {
        var me = $(this), indicator = $('#active-nav');
        indicator.animate({"top":me.position().top},{queue:false,duration:200});
    });

    /*
    MAKE ON/OFF SWITCHES WORK
    To set up: each div.gui-switch should contain two radio buttons.  One with an
    'off' value and one with an 'on' value.  Whichever is checked should be controlled
    by whether the node is actually on or off.
    */
    // Define a re-usable function to use any time a new node is created.
    // If the node is on or off, set switch class accordingly.
    function setGuiSwitch (i, e) {
        var me = $(e),
            isOn = (me.find('input[checked=checked]').attr('value').toLowerCase() === 'on');
        if (isOn) {
            me.removeClass('off').addClass('on');
        } else {
            me.removeClass('on').addClass('off');
        }
    }
    // When the document is ready, run setGuiSwitch on all on/off switches
    $('.gui-switch').each(setGuiSwitch);
    // When a switch changes, alter its class accordingly.
    $('.gui-switch input').on('change', function(e) {
        var that = $(this),
            theValue = that.attr('value').toLowerCase(),
            isChecked = (that.attr('checked') === 'checked'),
            theParent = that.closest('.gui-switch');
        if (theValue === 'on') {
            theParent.removeClass('off').addClass('on');
        } else if (theValue === 'off') {
            theParent.removeClass('on').addClass('off');
        }
    });
    // END CODE FOR ON/OFF SWITCHES

    /* MAKE CHECKBOXES WORK WHEN YOU CLICK THEM */
    $(document).on('change', '.gui-checkbox', function(e) {
        var me = $(this), parent = me.parent(); checked = me.attr('checked');
        if (checked) {
            parent.css('background-position', 'left top');
        } else {
            parent.css('background-position', 'left bottom');
        }
    });

    /* CODE FOR ALL THE TOOLTIPS */
    var wait;
    function emptyTips () {
        wait = setTimeout(function () {
            $('#tooltips').slideUp(function() {
                $('#display-tips').empty();
            });
        }, 500);
    }
    function displayTips (str) {
        var disp = $('#tooltips').css('display');
        if (disp === 'none') {
            $('#tooltips').slideDown();
        }
        $('#display-tips').html(str);
        clearTimeout(wait);
    }

    // Navigation

    // Basho Logo
    $(document).on('mouseover', '#basho-logo', function () {
        displayTips('Riak and Riak Control are products of Basho Technologies.  Visit our website to learn more.');
    }).on('mouseout', '#basho-logo', emptyTips);

    // Cluster link in navigation
    $(document).on('mouseover', '#nav-cluster', function () {
        displayTips('The cluster view allows you to add and remove nodes from your cluster as well as stop Riak on various nodes or mark them as down.  You will also be able to view percentages indicating how much ring data is owned by each node.');
    }).on('mouseout', '#nav-cluster', emptyTips);

    // Ring link in navigation
    $(document).on('mouseover', '#nav-ring', function () {
        displayTips('The ring view shows a list of your partitions indicating which node owns each partition.  You have the ability to apply filters to your view of the partitions and see indicators showing the status of various node workers, whether they are in active, fallback, or handoff states.');
    }).on('mouseout', '#nav-ring', emptyTips);

    // Snapshot link in navigation
    $(document).on('mouseover', '#nav-snapshot', function () {
        displayTips('Selecting the snapshot view commands Riak Control to gather some general information related to the current health of your cluster.  It is useful in quickly determining whether or not there are any issues to be concerned about.');
    }).on('mouseout', '#nav-snapshot', emptyTips);

    // Cluster View

    // Add new node area
    $(document).on('mouseover', '#add-node table', function () {
        displayTips('Type a node name (for example: dev2@127.0.0.1) into the text field and hit "Add Node" to add it to this cluster.  The node will then take ownership of partitions in the ring to help ensure balanced data across the cluster.');
    }).on('mouseout', '#add-node table', emptyTips);

    // Name of a node
    $(document).on('mouseover', '.node .name', function () {
        var name = $(this).text();
        displayTips('This node is named ' + name + '.  It is a member of this cluster.');
    }).on('mouseout', '.node .name', emptyTips);

    // View actions cluster sliders
    $(document).on('mouseover', '.more-actions-slider-box .gui-slider', function () {
        displayTips('Move the slider over to view possible actions for this node.  Move the slider back to hide those actions again.');
    }).on('mouseout', '.more-actions-slider-box .gui-slider', emptyTips);

    // Leave cluster button
    $(document).on('mouseover', '.leave-cluster-button', function () {
        displayTips('This will cause the node to begin relinquishing ownership of its data to other nodes in the cluster.  You will not be able to interact with the node via Riak Control during this process.  Once completed, Riak will shutdown on this node and it will leave the cluster.');
    }).on('mouseout', '.leave-cluster-button', emptyTips);

    // The 'Hosting Riak Control' message
    $(document).on('mouseover', '.current-host', function () {
        displayTips('This node cannot be shutdown or removed via Riak Control because it is currently hosting the app.');
    }).on('mouseout', '.current-host', emptyTips);

    // Markdown button
    $(document).on('mouseover', '.markdown-button', function () {
        displayTips('This button becomes active when the node becomes unreachable.  While in an unreachable state, a node may hinder cluster membership changes of other nodes.  Marking this node as "down" will allow other nodes to engage in membership changes unimpeded.');
    }).on('mouseout', '.markdown-button', emptyTips);

    // Shutdown button
    $(document).on('mouseover', '.shutdown-button', function () {
        displayTips('This button will stop the Riak process on this node.  If this button is not active, your node is already unreachable.  It will have to be restarted manually.');
    }).on('mouseout', '.shutdown-button', emptyTips);

    // Ring ownership percent
    $(document).on('mouseover', '.pct-box, .pct-arrows', function () {
        displayTips('This is the portion of the ring currently owned by this node.  If the up-arrow is lit, it means that this node is currently gaining ring data and will soon own a larger percentage.  If the down-arrow is lit, this node is currently handing ring data off to other nodes and will soon own a smaller percentage.');
    }).on('mouseout', '.pct-box, .pct-arrows', emptyTips);

    // Memory usage
    $(document).on('mouseover', '.membar-bg, .free-memory', function () {
        var parent = $(this).parent(),
            free_mem = parent.find('.free-memory').text(),
            erlang_mem, non_erlang_mem;
        if (free_mem.charAt(0) === '?') {
            displayTips('Because this node is currently unreachable, Riak Control is not able to assess its memory usage.');
        } else {
            free_mem = parseInt(free_mem);
            erlang_mem = parseInt(parent.find('.erlang-mem').attr('name'));
            non_erlang_mem = parseInt(parent.find('.non-erlang-mem').attr('name'));
            displayTips('The machine running this node currently has ' + free_mem + '% free memory.  Of the ' + (erlang_mem + non_erlang_mem) + '% currently in use, ' + erlang_mem + '% is being used by Riak and ' + non_erlang_mem + '% is being used by other processes.');
        }
    }).on('mouseout', '.membar-bg, .free-memory', emptyTips);

    // Node status
    $(document).on('mouseover', '.status-box', function () {
        var mytext = $(this).find('.status').text().toLowerCase();
        if (mytext === 'valid') {
            displayTips('This node is currently online and working.');
        } else if (mytext === 'unreachable') {
            displayTips('This node is unreachable.  Riak may need to be restarted or there may be other connectivity issues.  Cluster membership changes like "join" and "leave" cannot complete until this node is reachable or marked as "down".');
        } else if (mytext === 'down') {
            displayTips('This node has been marked as "down". While in this state it can not be interacted with but it will not impede cluster membership changes of other nodes.  To return to a "valid" state, simply restart Riak on this node.');
        } else if (mytext === 'leaving') {
            displayTips('This node is in process of leaving the cluster.  When it has finished relinquishing ownership and transferring data to other nodes, Riak will stop on this node and it will cease to be a member of the cluster.  You can not interact with this node during this process.');
        }
    }).on('mouseout', '.status-box', emptyTips);

    // Ring View

    // Ring filter
    $(document).on('mouseover', '#ring-filter', function () {
        displayTips('Select a node from the dropdown to view only the partitions owned by that node.  If you uncheck the boxes next to "Primary" or "Fallback", partitions in primary or fallback states will be removed from the view.');
    }).on('mouseout', '#ring-filter', emptyTips);

    // Partition owner
    $(document).on('mouseover', '.owner', function () {
        var partitionIndex = $(this).next().text();
        displayTips('The name of the node that owns this partition. (Partition Index: ' + partitionIndex + ')');
    }).on('mouseout', '.owner', emptyTips);

    // Worker Lights
    $(document).on('mouseover', '.kv-light, .pipe-light, .search-light', function () {
        var that = $(this);
        var texts;

        if (that.hasClass('kv-light')) {
            texts = {"status": that.find('.kv-status').text().toLowerCase(), "msg" : "Key-Value Store: "};
        } else if (that.hasClass('pipe-light')) {
            texts = {"status": that.find('.pipe-status').text().toLowerCase(), "msg" : "Pipeline Queue Process: "};
        } else if (that.hasClass('search-light')) {
            texts = {"status": that.find('.search-status').text().toLowerCase(), "msg" : "Riak Search: "};
        }

        if (texts.status === 'active') {
            displayTips(texts.msg + 'This node worker is active and ready.');
        } else if (texts.status === 'fallback') {
            displayTips(texts.msg + 'This node worker is not currently active.  This may be because its owner node is down or unreachable.  Operations normally handled by this node are currently in fallback to another node.');
        } else if (texts.status === 'handoff') {
            displayTips(texts.msg + 'This node worker is currently in the process of handing off its data to other nodes.');
        }
    }).on('mouseout', '.kv-light, .pipe-light, .search-light', emptyTips);

});<|endoftext|>


<commit_before>/**
 * Spaghetti's in built operators
 * @type {Object}
 */
module.exports = {
    print(stack) {
        let jumpTo = stack.pop(),
            numArgs = stack.pop();

        for (var i = 0; i < numArgs; i++) {
            console.log(stack.pop());
        }
        return {
            jumpTo,
            stack
        };
    }
};
<commit_msg>Add addition operator<commit_after>/**
 * Spaghetti's in built operators
 * @type {Object}
 */
module.exports = {
    print(stack) {
        let jumpTo = stack.pop(),
            numArgs = stack.pop();

        for (var i = 0; i < numArgs; i += 1) {
            console.log(stack.pop());
        }
        return {
            jumpTo,
            stack
        };
    },
    add(stack) {
        let jumpTo = stack.pop(),
            numArgs = stack.pop(),
            sum = 0;

        for (var i = 0; i < numArgs; i += 1) {
            sum += stack.pop();
        }
        stack.push(sum);
        return {
            jumpTo,
            stack
        }
    }
};
<|endoftext|>


<commit_before>/**
 * This is the callback supplied by the consumer that handles the returned location template XML.
 *
 * @locationdescriptorcallback locationDescriptorCallback
 * @param {string} Returned location descriptor
 */

 /**
 * @param {locationDescriptorCallback} locationdescriptorcallback - The callback that handles the returned location template
 * @returns {Object} sQuery - Returns the sQuery object
 * @public
 */
S.fn.getlocationdescriptor = function (url, locationdescriptorcallback) {

  if ("function" === typeof locationdescriptorcallback ) {

    // Request is asynchronous; callback function must be provided
    // and it must accept one parameter for the returned value.
    $.get(url,

      function(data) {

        locationdescriptorcallback(data);

      }, 'xml');

    return this;

  } else {

    throw new Error("getlocationdescriptor() :: Callback function must be provided.");

  }

}; //getlocationdescriptor

/**
 * @param {string} xmllocationdescriptor - The location template XML
 * @returns {Object} objLocationDetails - Returns the location data record format
 * @public
 */

S.fn.getlocationdetails = function (xmllocationdescriptor) {

  if (this.is("XMLDocument",xmllocationdescriptor)) {

    // Each node is referenced below to illustrate the XML structure
    // although we could get to the node of interest directly

    var

        $xmlLocationDescriptor = $( xmllocationdescriptor ),
        $xmlResultTemplateResponse = $xmlLocationDescriptor.find('GetResultTemplateResponse'),
        $xmlResultStructure = $xmlLocationDescriptor.find('resultStructure'),
        $xmlDataRecord = $xmlResultStructure.find('DataRecord'),
        $xmlTime = $xmlDataRecord.find("field[name='time']"),
        $xmlLocation = $xmlDataRecord.find("field[name='location']"),
        $xmlLocationVector = $xmlLocation.find("Vector"),
        vectorCoordinateSystem = $xmlLocationVector.attr('referenceFrame'),
        $xmlLocationCoordinates = [],
        $xmlResultEncoding = $xmlResultTemplateResponse.find("resultEncoding"),
        objLocationDetails = new Object();

    objLocationDetails.tokenseparator = $xmlResultEncoding.find("TextEncoding").attr("tokenSeparator");
    objLocationDetails.decimalsepartor = $xmlResultEncoding.find("TextEncoding").attr("decimalSeparator");
    objLocationDetails.coordinatesystem = vectorCoordinateSystem;

    // Save coordinates
    $xmlLocationVector.find('coordinate').each(function(i,coordinate) {
        $xmlLocationCoordinates[i] = $(this);
    });

    objLocationDetails.tokens = [];

    var objToken = new Object();
    objToken.name = 'time';
    objToken.zone = $xmlTime.find('Time').attr('referenceFrame');
    objLocationDetails.tokens[0] = objToken;

    for (var i = 0, l = $xmlLocationCoordinates.length; l > i; ++i) {
      var objToken = new Object();
      objToken.name = $xmlLocationCoordinates[i].attr('name');;
      objToken.definition = $xmlLocationCoordinates[i].find('Quantity').attr('definition');
      objToken.uom = $xmlLocationCoordinates[i].find('Quantity').find('uom').attr('code');
      objToken.coordinatesystem = vectorCoordinateSystem;
      objLocationDetails.tokens[i+1] = objToken;
    }

    return objLocationDetails;

  } else {

    throw new Error("getlocationdetails() :: No location template document provided.");
  }

}; // getlocationdetails
<commit_msg>Added UOM to time<commit_after>/**
 * This is the callback supplied by the consumer that handles the returned location template XML.
 *
 * @locationdescriptorcallback locationDescriptorCallback
 * @param {string} Returned location descriptor
 */

 /**
 * @param {locationDescriptorCallback} locationdescriptorcallback - The callback that handles the returned location template
 * @returns {Object} sQuery - Returns the sQuery object
 * @public
 */
S.fn.getlocationdescriptor = function (url, locationdescriptorcallback) {

  if ("function" === typeof locationdescriptorcallback ) {

    // Request is asynchronous; callback function must be provided
    // and it must accept one parameter for the returned value.
    $.get(url,

      function(data) {

        locationdescriptorcallback(data);

      }, 'xml');

    return this;

  } else {

    throw new Error("getlocationdescriptor() :: Callback function must be provided.");

  }

}; //getlocationdescriptor

/**
 * @param {string} xmllocationdescriptor - The location template XML
 * @returns {Object} objLocationDetails - Returns the location data record format
 * @public
 */

S.fn.getlocationdetails = function (xmllocationdescriptor) {

  if (this.is("XMLDocument",xmllocationdescriptor)) {

    // Each node is referenced below to illustrate the XML structure
    // although we could get to the node of interest directly

    var

        $xmlLocationDescriptor = $( xmllocationdescriptor ),
        $xmlResultTemplateResponse = $xmlLocationDescriptor.find('GetResultTemplateResponse'),
        $xmlResultStructure = $xmlLocationDescriptor.find('resultStructure'),
        $xmlDataRecord = $xmlResultStructure.find('DataRecord'),
        $xmlTime = $xmlDataRecord.find("field[name='time']"),
        $xmlLocation = $xmlDataRecord.find("field[name='location']"),
        $xmlLocationVector = $xmlLocation.find("Vector"),
        vectorCoordinateSystem = $xmlLocationVector.attr('referenceFrame'),
        $xmlLocationCoordinates = [],
        $xmlResultEncoding = $xmlResultTemplateResponse.find("resultEncoding"),
        objLocationDetails = new Object();

    objLocationDetails.tokenseparator = $xmlResultEncoding.find("TextEncoding").attr("tokenSeparator");
    objLocationDetails.decimalsepartor = $xmlResultEncoding.find("TextEncoding").attr("decimalSeparator");
    objLocationDetails.coordinatesystem = vectorCoordinateSystem;

    // Save coordinates
    $xmlLocationVector.find('coordinate').each(function(i,coordinate) {
        $xmlLocationCoordinates[i] = $(this);
    });

    objLocationDetails.tokens = [];

    var objToken = new Object();
    objToken.name = 'time';
    objToken.zone = $xmlTime.find('Time').attr('referenceFrame');
    objToken.uom = $xmlTime.find('Time').find('uom').attr('xlink:href');
    objLocationDetails.tokens[0] = objToken;

    for (var i = 0, l = $xmlLocationCoordinates.length; l > i; ++i) {
      var objToken = new Object();
      objToken.name = $xmlLocationCoordinates[i].attr('name');;
      objToken.definition = $xmlLocationCoordinates[i].find('Quantity').attr('definition');
      objToken.uom = $xmlLocationCoordinates[i].find('Quantity').find('uom').attr('code');
      objToken.coordinatesystem = vectorCoordinateSystem;
      objLocationDetails.tokens[i+1] = objToken;
    }

    return objLocationDetails;

  } else {

    throw new Error("getlocationdetails() :: No location template document provided.");
  }

}; // getlocationdetails
<|endoftext|>


<commit_before>/** @module delite/BoilerplateTextbox */
define([
	"delite/register",
	"delite/uacss",
	"delite/Container",
	"delite/FormValueWidget",
	"delite/Widget",
	"delite/handlebars!./BoilerplateTextbox/BoilerplateTextbox.html",
	"requirejs-dplugins/jquery!attributes/classes",
	"delite/activationTracker",
	"delite/theme!./BoilerplateTextbox/themes/{{theme}}/BoilerplateTextbox.css"
], function (
	register,
	has,
	Container,
	FormValueWidget,
	Widget,
	template,
	$
) {
	"use strict";

	/**
	 * Non-editable section, boilerplate text.
	 *
	 * Creator should set:
	 *
	 * - textContent
	 */
	var Boilerplate = register("d-btb-boilerplate", [HTMLElement, Widget], {});

	/**
	 * Base class for editable fields in a BoilerplateTextbox.
	 *
	 * Creator should set the following properties/attributes:
	 *
	 * - value
	 * - placeholder
	 * - aria-label
	 *
	 * Emits "completed" event if caret should automatically move to next element.
	 */
	var Field = register("d-btb-field", [HTMLInputElement, Widget], {
		refreshRendering: function (oldVals) {
			if ("placeholder" in oldVals) {
				var computedWidth = this.computeWidth();
				if (computedWidth) {
					this.style.width = computedWidth;
				}
			}
		},

		/**
		 * Figure out the width of this field based on the placeholder.
		 * If width is specified in CSS then override this method to return null.
		 */
		computeWidth: function () {
			return this.placeholder.length + "em";
		}
	});

	/**
	 * Generic number field.  Set placeholder, min, and max properties.
	 */
	var NumberField = register("d-btb-number-field", [Field], {
		/**
		 * Number of characters user has typed into this field since it was focused.
		 */
		charactersTyped: 0,

		createdCallback: function () {
			this.on("focus", this.focusHandler.bind(this));
			this.on("keydown", this.keydownHandler.bind(this));

			// Set properties so that:
			// 1. When editing field, numeric virtual keyboard appears on mobile devices.
			// 2. Up/down spinner *doesn't* appear on Webkit and Firefox desktop (there's no room for it).
			//    It appears with type=number although it can be hidden with CSS.
			// 3. Firefox allows display of leading zeros. (It's not allowed for type=number, see
			//    http://stackoverflow.com/questions/8437529/html5-input-type-number-removes-leading-zero.)
			// 4. Chrome allows us to move the caret to the end of the text.  (It's not allowed for type=number,
			//    see https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange.)
			// 5. Avoid Android behavior where evt.key = 229 instead of the actual digit typed, see
			//    http://stackoverflow.com/questions/30743490/
			//    capture-keys-typed-on-android-virtual-keyboard-using-javascript.
			//
			// I know setting type="tel" is weird.  It might only be needed for older browsers,
			// otherwise setting pattern should be sufficient.
			this.type = "tel";
			this.pattern = "[0-9]*";
			this.autocomplete = "off";
		},

		focusHandler: function () {
			this.charactersTyped = 0;
			this.selectionStart = this.value.length;		// put caret at end
		},

		/**
		 * Returns true if the input is complete and BoilerplateTextbox should
		 * automatically advance to next field.  Input is considered complete if:
		 *
		 * 1. User has typed the maximum number of digits.
		 * 2. Typing another digit (any digit) would make the value exceed this.max.
		 */
		inputComplete: function () {
			return this.charactersTyped >= this.placeholder.length || parseInt(this.value + "0", 10) > this.max;
		},

		keydownHandler: function (evt) {
			var char = evt.key;

			// Let the browser handle tab and shift-tab.
			if (char === "Tab") {
				return;
			}

			// Handle all other keys programatically, don't let the browser insert the character directly.
			evt.preventDefault();

			if (char === "Delete" || char === "Backspace") {
				this.value = "";
				this.charactersTyped = 0;
				this.emit("input");
			} else if (this.charactersTyped >= this.placeholder.length) {
				return;
			} else if (/[0-9]/.test(char)) {
				var newValue;
				if (this.charactersTyped === 0) {
					// For the first character the user types, replace the boilerplate text (ex: "yyyy")
					// with zeros followed by the character the user typed.
					newValue = (new Array(this.placeholder.length)).join("0") + char;
				} else {
					// Otherwise, slide the other characters over and insert new character at right,
					// for example if the user types "3" then "0002" is changed to "0023".
					newValue = this.value.substr(1) + char;
				}

				// If the new value exceeds the maximum value, then ignore the keystroke.
				if (this.max && parseInt(newValue, 10) > parseInt(this.max, 10)) {
					return;
				}

				// If the new digit makes it impossible to meet the minimum value, ignore the
				// keystroke.  For example, if the field is two characters with a min of
				// 50 and the first character the user types is 4.
				var maxPossibleFutureVal = newValue +
					(new Array(this.placeholder.length - this.charactersTyped)).join("9");
				if (this.min && parseInt(maxPossibleFutureVal, 10) < parseInt(this.min, 10)) {
					return;
				}

				this.value = newValue;
				this.charactersTyped++;

				this.emit("input");

				// Send "completed" event if focus should automatically move to next field.
				if (this.inputComplete()) {
					this.emit("completed");
				}
			}
		}
	});

	/**
	 * A replacement for an `<input>` that enforces a certain pattern by having editable areas separated
	 * by boilerplate text.
	 *
	 * The editable areas and boilerplate text are children of this widget and must exist by the time
	 * `render()` completes.
	 */
	var BoilerplateTextbox = register("d-boilerplate-textbox", [HTMLElement, Container, FormValueWidget], {
		baseClass: "d-boilerplate-textbox",

		template: template,

		createdCallback: function () {
			this.on("delite-activated", this.activatedHandler.bind(this));
			this.on("delite-deactivated", this.deactivatedHandler.bind(this));
		},

		postRender: function () {
			this.on("input", this.nestedInputHandler.bind(this), this.containerNode);
			this.on("change", this.nestedChangeHandler.bind(this), this.containerNode);
			this.on("completed", this.completedHandler.bind(this), this.containerNode);

			// Change tabStops to point to all the <input> nodes so that FormWidget#refreshRendering()
			// sets tabIndex, disabled, and readonly properties on those <input> nodes.
			var inputs = [].slice.call(this.containerNode.querySelectorAll("input"));
			var tabStops = [];
			inputs.forEach(function (input) {
				this["field" + tabStops.length] = input;
				tabStops.push("field" + tabStops.length);
			}, this);
			this.tabStops = tabStops;
		},

		/**
		 * Set values of `<input>` nodes according to specified value.
		 * String must exactly match formatting of `<input>` placeholder text
		 * combined with boilerplate text.
		 * @param value
		 */
		setInputValues: function (value) {
			var start = 0;
			Array.prototype.forEach.call(this.containerNode.children, function (section) {
				var length = (section.placeholder || section.textContent).length;
				if ("value" in section) {
					section.value = value ? value.substr(start, length) : "";
				}
				start += length;
			});
		},

		refreshRendering: function (oldVals) {
			if ("value" in oldVals && !this.processingUserInput) {
				this.setInputValues(this.value);
			}
		},

		activatedHandler: function () {
			// When the BoilerplateTextbox gets focus, focus the first <input>.
			this.defer(function () {
				this.containerNode.querySelector("input").focus();
			});
			$(this).addClass("d-focused");
		},

		deactivatedHandler: function () {
			// When the BoilerplateTextbox loses focus, fire the "change" event.
			this.handleOnChange(this.value);
			$(this).removeClass("d-focused");
		},

		/**
		 * Get value of widget according to values of nested `<input>` nodes.
		 * @returns {*}
		 */
		getValue: function () {
			// Return concatenated values of fields.
			// If any of the fields are unset then return "".
			var sections = [].slice.call(this.containerNode.children);
			if (sections.every(function (section) { return section.value || section.textContent; })) {
				return sections.map(function (section) {
					return section.value || section.textContent;
				}).join("");
			} else {
				return "";
			}
		},

		/**
		 * Handler for when user types into one of the nested `<input>`'s.
		 * @param evt
		 */
		nestedInputHandler: function (evt) {
			evt.stopPropagation();

			this.processingUserInput = true;
			this.defer(function () {
				this.processingUserInput = false;
			}, 1);

			this.handleOnInput(this.getValue());
		},

		/**
		 * Handler for when nested `<input>` emits a "change" event.
		 * @param evt
		 */
		nestedChangeHandler: function (evt) {
			evt.stopPropagation();
		},

		/**
		 * Handler for when a nested `<input>` declares that user has finished setting the value.
		 * Advances to the next `<input>` if there is one.
		 */
		completedHandler: function (evt) {
			var inputs = [].slice.call(this.containerNode.querySelectorAll("input"));
			var nextIdx = inputs.indexOf(evt.target) + 1;
			if (nextIdx < inputs.length) {
				inputs[nextIdx].focus();
			}
		},

		setAttribute: register.superCall(function (sup) {
			return function (name, value) {
				sup.apply(this, arguments);

				// Workaround iOS limitation where VoiceOver doesn't announce label of container.
				if(has("ios")) {
					var label;
					if (name === "aria-label") {
						label = value;
					} else if (name === "aria-labelledby") {
						var labelNode = this.ownerDocument.getElementById(value);
						label = labelNode && labelNode.textContent;
					}
					if (label) {
						var inputs = [].slice.call(this.containerNode.querySelectorAll("input"));
						inputs.forEach(function (field) {
							if (!field.origAriaLabel) {
								field.origAriaLabel = field.getAttribute("aria-label");
							}
							field.setAttribute("aria-label", label + " " + field.origAriaLabel);
						});
					}
				}
			};
		})
	});

	BoilerplateTextbox.Boilerplate = Boilerplate;
	BoilerplateTextbox.Field = Field;
	BoilerplateTextbox.NumberField = NumberField;

	return BoilerplateTextbox;
});
<commit_msg>JSHint, refs #698.<commit_after>/** @module delite/BoilerplateTextbox */
define([
	"delite/register",
	"delite/uacss",
	"delite/Container",
	"delite/FormValueWidget",
	"delite/Widget",
	"delite/handlebars!./BoilerplateTextbox/BoilerplateTextbox.html",
	"requirejs-dplugins/jquery!attributes/classes",
	"delite/activationTracker",
	"delite/theme!./BoilerplateTextbox/themes/{{theme}}/BoilerplateTextbox.css"
], function (
	register,
	has,
	Container,
	FormValueWidget,
	Widget,
	template,
	$
) {
	"use strict";

	/**
	 * Non-editable section, boilerplate text.
	 *
	 * Creator should set:
	 *
	 * - textContent
	 */
	var Boilerplate = register("d-btb-boilerplate", [HTMLElement, Widget], {});

	/**
	 * Base class for editable fields in a BoilerplateTextbox.
	 *
	 * Creator should set the following properties/attributes:
	 *
	 * - value
	 * - placeholder
	 * - aria-label
	 *
	 * Emits "completed" event if caret should automatically move to next element.
	 */
	var Field = register("d-btb-field", [HTMLInputElement, Widget], {
		refreshRendering: function (oldVals) {
			if ("placeholder" in oldVals) {
				var computedWidth = this.computeWidth();
				if (computedWidth) {
					this.style.width = computedWidth;
				}
			}
		},

		/**
		 * Figure out the width of this field based on the placeholder.
		 * If width is specified in CSS then override this method to return null.
		 */
		computeWidth: function () {
			return this.placeholder.length + "em";
		}
	});

	/**
	 * Generic number field.  Set placeholder, min, and max properties.
	 */
	var NumberField = register("d-btb-number-field", [Field], {
		/**
		 * Number of characters user has typed into this field since it was focused.
		 */
		charactersTyped: 0,

		createdCallback: function () {
			this.on("focus", this.focusHandler.bind(this));
			this.on("keydown", this.keydownHandler.bind(this));

			// Set properties so that:
			// 1. When editing field, numeric virtual keyboard appears on mobile devices.
			// 2. Up/down spinner *doesn't* appear on Webkit and Firefox desktop (there's no room for it).
			//    It appears with type=number although it can be hidden with CSS.
			// 3. Firefox allows display of leading zeros. (It's not allowed for type=number, see
			//    http://stackoverflow.com/questions/8437529/html5-input-type-number-removes-leading-zero.)
			// 4. Chrome allows us to move the caret to the end of the text.  (It's not allowed for type=number,
			//    see https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange.)
			// 5. Avoid Android behavior where evt.key = 229 instead of the actual digit typed, see
			//    http://stackoverflow.com/questions/30743490/
			//    capture-keys-typed-on-android-virtual-keyboard-using-javascript.
			//
			// I know setting type="tel" is weird.  It might only be needed for older browsers,
			// otherwise setting pattern should be sufficient.
			this.type = "tel";
			this.pattern = "[0-9]*";
			this.autocomplete = "off";
		},

		focusHandler: function () {
			this.charactersTyped = 0;
			this.selectionStart = this.value.length;		// put caret at end
		},

		/**
		 * Returns true if the input is complete and BoilerplateTextbox should
		 * automatically advance to next field.  Input is considered complete if:
		 *
		 * 1. User has typed the maximum number of digits.
		 * 2. Typing another digit (any digit) would make the value exceed this.max.
		 */
		inputComplete: function () {
			return this.charactersTyped >= this.placeholder.length || parseInt(this.value + "0", 10) > this.max;
		},

		keydownHandler: function (evt) {
			var char = evt.key;

			// Let the browser handle tab and shift-tab.
			if (char === "Tab") {
				return;
			}

			// Handle all other keys programatically, don't let the browser insert the character directly.
			evt.preventDefault();

			if (char === "Delete" || char === "Backspace") {
				this.value = "";
				this.charactersTyped = 0;
				this.emit("input");
			} else if (this.charactersTyped >= this.placeholder.length) {
				return;
			} else if (/[0-9]/.test(char)) {
				var newValue;
				if (this.charactersTyped === 0) {
					// For the first character the user types, replace the boilerplate text (ex: "yyyy")
					// with zeros followed by the character the user typed.
					newValue = (new Array(this.placeholder.length)).join("0") + char;
				} else {
					// Otherwise, slide the other characters over and insert new character at right,
					// for example if the user types "3" then "0002" is changed to "0023".
					newValue = this.value.substr(1) + char;
				}

				// If the new value exceeds the maximum value, then ignore the keystroke.
				if (this.max && parseInt(newValue, 10) > parseInt(this.max, 10)) {
					return;
				}

				// If the new digit makes it impossible to meet the minimum value, ignore the
				// keystroke.  For example, if the field is two characters with a min of
				// 50 and the first character the user types is 4.
				var maxPossibleFutureVal = newValue +
					(new Array(this.placeholder.length - this.charactersTyped)).join("9");
				if (this.min && parseInt(maxPossibleFutureVal, 10) < parseInt(this.min, 10)) {
					return;
				}

				this.value = newValue;
				this.charactersTyped++;

				this.emit("input");

				// Send "completed" event if focus should automatically move to next field.
				if (this.inputComplete()) {
					this.emit("completed");
				}
			}
		}
	});

	/**
	 * A replacement for an `<input>` that enforces a certain pattern by having editable areas separated
	 * by boilerplate text.
	 *
	 * The editable areas and boilerplate text are children of this widget and must exist by the time
	 * `render()` completes.
	 */
	var BoilerplateTextbox = register("d-boilerplate-textbox", [HTMLElement, Container, FormValueWidget], {
		baseClass: "d-boilerplate-textbox",

		template: template,

		createdCallback: function () {
			this.on("delite-activated", this.activatedHandler.bind(this));
			this.on("delite-deactivated", this.deactivatedHandler.bind(this));
		},

		postRender: function () {
			this.on("input", this.nestedInputHandler.bind(this), this.containerNode);
			this.on("change", this.nestedChangeHandler.bind(this), this.containerNode);
			this.on("completed", this.completedHandler.bind(this), this.containerNode);

			// Change tabStops to point to all the <input> nodes so that FormWidget#refreshRendering()
			// sets tabIndex, disabled, and readonly properties on those <input> nodes.
			var inputs = [].slice.call(this.containerNode.querySelectorAll("input"));
			var tabStops = [];
			inputs.forEach(function (input) {
				this["field" + tabStops.length] = input;
				tabStops.push("field" + tabStops.length);
			}, this);
			this.tabStops = tabStops;
		},

		/**
		 * Set values of `<input>` nodes according to specified value.
		 * String must exactly match formatting of `<input>` placeholder text
		 * combined with boilerplate text.
		 * @param value
		 */
		setInputValues: function (value) {
			var start = 0;
			Array.prototype.forEach.call(this.containerNode.children, function (section) {
				var length = (section.placeholder || section.textContent).length;
				if ("value" in section) {
					section.value = value ? value.substr(start, length) : "";
				}
				start += length;
			});
		},

		refreshRendering: function (oldVals) {
			if ("value" in oldVals && !this.processingUserInput) {
				this.setInputValues(this.value);
			}
		},

		activatedHandler: function () {
			// When the BoilerplateTextbox gets focus, focus the first <input>.
			this.defer(function () {
				this.containerNode.querySelector("input").focus();
			});
			$(this).addClass("d-focused");
		},

		deactivatedHandler: function () {
			// When the BoilerplateTextbox loses focus, fire the "change" event.
			this.handleOnChange(this.value);
			$(this).removeClass("d-focused");
		},

		/**
		 * Get value of widget according to values of nested `<input>` nodes.
		 * @returns {*}
		 */
		getValue: function () {
			// Return concatenated values of fields.
			// If any of the fields are unset then return "".
			var sections = [].slice.call(this.containerNode.children);
			if (sections.every(function (section) { return section.value || section.textContent; })) {
				return sections.map(function (section) {
					return section.value || section.textContent;
				}).join("");
			} else {
				return "";
			}
		},

		/**
		 * Handler for when user types into one of the nested `<input>`'s.
		 * @param evt
		 */
		nestedInputHandler: function (evt) {
			evt.stopPropagation();

			this.processingUserInput = true;
			this.defer(function () {
				this.processingUserInput = false;
			}, 1);

			this.handleOnInput(this.getValue());
		},

		/**
		 * Handler for when nested `<input>` emits a "change" event.
		 * @param evt
		 */
		nestedChangeHandler: function (evt) {
			evt.stopPropagation();
		},

		/**
		 * Handler for when a nested `<input>` declares that user has finished setting the value.
		 * Advances to the next `<input>` if there is one.
		 */
		completedHandler: function (evt) {
			var inputs = [].slice.call(this.containerNode.querySelectorAll("input"));
			var nextIdx = inputs.indexOf(evt.target) + 1;
			if (nextIdx < inputs.length) {
				inputs[nextIdx].focus();
			}
		},

		setAttribute: register.superCall(function (sup) {
			return function (name, value) {
				sup.apply(this, arguments);

				// Workaround iOS limitation where VoiceOver doesn't announce label of container.
				if (has("ios")) {
					var label;
					if (name === "aria-label") {
						label = value;
					} else if (name === "aria-labelledby") {
						var labelNode = this.ownerDocument.getElementById(value);
						label = labelNode && labelNode.textContent;
					}
					if (label) {
						var inputs = [].slice.call(this.containerNode.querySelectorAll("input"));
						inputs.forEach(function (field) {
							if (!field.origAriaLabel) {
								field.origAriaLabel = field.getAttribute("aria-label");
							}
							field.setAttribute("aria-label", label + " " + field.origAriaLabel);
						});
					}
				}
			};
		})
	});

	BoilerplateTextbox.Boilerplate = Boilerplate;
	BoilerplateTextbox.Field = Field;
	BoilerplateTextbox.NumberField = NumberField;

	return BoilerplateTextbox;
});
<|endoftext|>


<commit_before>const BasePlugin = require('../../utils/BasePlugin');

class ManageMemberPlugin extends BasePlugin {
  init() {
    this.initDB();
    this.initCommands();
    this.initListener();
  }

  initDB() {
    // Setup music DB
    this.membersDB = this.getDB('songs', true);
    this.fieldsDB.ensureIndex({ fieldName: 'name' }, function (err) {
      console.error("[songsDB] 'name' field error : " + err);
    });
    this.fieldsDB.ensureIndex({ fieldName: 'link', unique: true }, function (err) {
      console.error("[songsDB] 'link' field error : " + err);
    });
    this.fieldsDB.ensureIndex({ fieldName: 'playCount' }, function (err) {
      console.error("[songsDB] 'playCount' field error : " + err);
    });

    // Setup the config DB
    this.configDB = this.getDB('config');
    this.configDB.findOne({}, function(err, config) {
      if (doc != null) {
        // Load the default values into the DB
        config = {
          MUSIC_CHANNEL_ID: "246230860645269504",   // Channel to monitor for new music links
          VOICE_CHANNEL_ID: "249857283717201920",   // Channel to play music
          AUTO_ADD_NEW_LINKS: true                  // Whether to auto add new links from MUSIC_CHANNEL_ID to playlist
        };

        this.configDB.insert(config);
      }

      this.MUSIC_CHANNEL_ID = config.MUSIC_CHANNEL_ID;
      this.VOICE_CHANNEL_ID = config.VOICE_CHANNEL_ID;
      this.AUTO_ADD_NEW_LINKS = config.AUTO_ADD_NEW_LINKS;
    });
  }

  initCommands() {
    /*
     *  MusicBot related commands
     */
     this.commands = [];
  }

  initListener() {
    this.client.on('message', message => {
      if (!this.AUTO_ADD_NEW_LINKS || message.channel.id != this.MUSIC_CHANNEL_ID) {
        return;
      }

      this.log(`Got new message ${message.content}`);
    }
  }
}<commit_msg>Add commands for music bot to set channel IDs<commit_after>const BasePlugin = require('../../utils/BasePlugin');

class ManageMemberPlugin extends BasePlugin {
  init() {
    this.initDB();
    this.initCommands();
    this.initListener();
  }

  initDB() {
    // Setup music DB
    this.membersDB = this.getDB('songs', true);
    this.fieldsDB.ensureIndex({ fieldName: 'name' }, function (err) {
      console.error("[songsDB] 'name' field error : " + err);
    });
    this.fieldsDB.ensureIndex({ fieldName: 'link', unique: true }, function (err) {
      console.error("[songsDB] 'link' field error : " + err);
    });
    this.fieldsDB.ensureIndex({ fieldName: 'playCount' }, function (err) {
      console.error("[songsDB] 'playCount' field error : " + err);
    });

    // Setup the config DB
    this.configDB = this.getDB('config');
    this.configDB.findOne({}, function(err, config) {
      if (doc != null) {
        // Load the default values into the DB
        config = {
          MUSIC_CHANNEL_ID: null,   // Channel to monitor for new music links
          VOICE_CHANNEL_ID: null,   // Channel to play music
          AUTO_ADD_NEW_LINKS: true                  // Whether to auto add new links from MUSIC_CHANNEL_ID to playlist
        };

        this.configDB.insert(config);
      }

      this.MUSIC_CHANNEL_ID = config.MUSIC_CHANNEL_ID;
      this.VOICE_CHANNEL_ID = config.VOICE_CHANNEL_ID;
      this.AUTO_ADD_NEW_LINKS = config.AUTO_ADD_NEW_LINKS;
      this.configID = config._id;
    });
  }

  initCommands() {
    /*
     *  MusicBot related commands
     */
     this.commands = [];

     this.commands.push(new Command(
       'setMusicChannelID',
       'Set music channel for MusicBot',
       this.setMusicChannelID.bind(this),
       ['ADMINISTRATOR']
     ));

     this.commands.push(new Command(
       'setVoiceChannelID',
       'Set voice channel for MusicBot',
       this.setVoiceChannelID.bind(this),
       ['ADMINISTRATOR']
     ));
  }

  initListener() {
    this.client.on('message', message => {
      if (!this.AUTO_ADD_NEW_LINKS || message.channel.id != this.MUSIC_CHANNEL_ID) {
        return;
      }

      this.log(`Got new message ${message.content}`);
    }
  }

  getCommands() {
    return this.commands;
  }

  setMusicChannelID(message) {
    const args = message.split(' ');

    this.configDB.update(
      { _id: this.configID },
      { $set: { MUSIC_CHANNEL_ID: args[0] } },
      {},
      function (err) {
        if (err) {
          return err;
        } else {
          return `Set music channel ID to {args[0]}`;
        }
      }
    );
  }

  setVoiceChannelID(message) {
    const args = message.split(' ');

    this.configDB.update(
      { _id: this.configID },
      { $set: { VOICE_CHANNEL_ID: args[0] } },
      {},
      function (err) {
        if (err) {
          return err;
        } else {
          return `Set voice channel ID to {args[0]}`;
        }
      }
    );
  }
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2013 André Bargull
 * Alle Rechte vorbehalten / All Rights Reserved.  Use is subject to license terms.
 *
 * <https://github.com/anba/es6draft>
 */

const {
  assertTrue,
  assertNativeFunction,
} = Assert;

// Test access to built-in functions:
// - DeferredConstructionFunction
// - ResolvePromiseFunction
// - RejectPromiseFunction
// - IdentityFunction
// - ThrowerFunction

// Simple, hack-ish way to break out of promise error handling...
function reportFailure(e) {
  nextTick(() => { throw e });
}

// Access to 'DeferredConstructionFunction'
{
  function F(resolver) {
    Object.assign(this, {resolver});
    resolver(() => {}, () => {});
  }

  let o = Promise.resolve.call(F);
  assertNativeFunction(o.resolver, undefined, 2);
}

// Access to 'ResolvePromiseFunction' and 'RejectPromiseFunction'
{
  let result = {};
  new Promise((resolve, reject) => {
    Object.assign(result, {resolve, reject});
  });
  assertNativeFunction(result.resolve, undefined, 1);
  assertNativeFunction(result.reject, undefined, 1);
}

// Access to 'IdentityFunction' and 'ThrowerFunction'
// Access to 'ResolvePromiseFunction' and 'RejectPromiseFunction'
{
  let skip = 2; // 2 = then + catch
  class XPromise extends Promise {
    then(fulfill, reject) {
      if (skip > 0) {
        skip -= 1;
      } else {
        assertNativeFunction(fulfill, undefined, 1);
        assertNativeFunction(reject, undefined, 1);
      }
      return super(fulfill, reject);
    }

    static deferred() {
      let result = {};
      result.promise = new this((resolve, reject) => {
        Object.assign(result, {resolve, reject});
      });
      return result;
    }
  }
  let d = XPromise.deferred();
  d.promise.then().catch(reportFailure);
  d.resolve(XPromise.resolve());
}
<commit_msg>Test behaviour of identity and thrower function<commit_after>/*
 * Copyright (c) 2012-2013 André Bargull
 * Alle Rechte vorbehalten / All Rights Reserved.  Use is subject to license terms.
 *
 * <https://github.com/anba/es6draft>
 */

const {
  fail,
  assertTrue,
  assertSame,
  assertUndefined,
  assertNativeFunction,
} = Assert;

// Test access to built-in functions:
// - DeferredConstructionFunction
// - ResolvePromiseFunction
// - RejectPromiseFunction
// - IdentityFunction
// - ThrowerFunction

// Simple, hack-ish way to break out of promise error handling...
function reportFailure(e) {
  nextTick(() => { throw e });
}

// Access to 'DeferredConstructionFunction'
{
  function F(resolver) {
    Object.assign(this, {resolver});
    resolver(() => {}, () => {});
  }

  let o = Promise.resolve.call(F);
  assertNativeFunction(o.resolver, undefined, 2);
}

// Access to 'ResolvePromiseFunction' and 'RejectPromiseFunction'
{
  let result = {};
  new Promise((resolve, reject) => {
    Object.assign(result, {resolve, reject});
  });
  assertNativeFunction(result.resolve, undefined, 1);
  assertNativeFunction(result.reject, undefined, 1);
}

// Access to 'IdentityFunction' and 'ThrowerFunction'
// Access to 'ResolvePromiseFunction' and 'RejectPromiseFunction'
{
  let stepCount = 0;
  let builtins = {
    identity: void 0,
    thrower: void 0,
    resolvePromise: void 0,
    rejectPromise: void 0,
  };
  class XPromise extends Promise {
    then(fulfill, reject) {
      let step = ++stepCount;
      assertTrue(1 <= step && step <= 5, `step = ${step}`);
      switch (step) {
        case 1:
          assertUndefined(fulfill);
          assertUndefined(reject);
          break;
        case 2:
          assertSame(testBuiltinFunctions, fulfill);
          assertUndefined(reject);
          break;
        case 3:
          assertUndefined(fulfill);
          assertSame(reportFailure, reject);
          break;
        case 4:
          builtins.identity = fulfill;
          builtins.thrower = reject;
          assertNativeFunction(fulfill, undefined, 1);
          assertNativeFunction(reject, undefined, 1);
          break;
        case 5:
          builtins.resolvePromise = fulfill;
          builtins.rejectPromise = reject;
          assertNativeFunction(fulfill, undefined, 1);
          assertNativeFunction(reject, undefined, 1);
          break;
      }
      return super(fulfill, reject);
    }

    static deferred() {
      let result = {};
      result.promise = new this((resolve, reject) => {
        Object.assign(result, {resolve, reject});
      });
      return result;
    }
  }

  function testBuiltinFunctions() {
    assertSame(5, stepCount);
    testIdentityFunction(builtins.identity);
    testThrowerFunction(builtins.thrower);

    // calling these functions should have no effect
    builtins.resolvePromise();
    builtins.rejectPromise();
  }

  function testIdentityFunction(f) {
    for (let v of [void 0, null, 1, "", {}, [], () => {}]) {
      assertSame(v, f(v));
    }
  }

  function testThrowerFunction(f) {
    for (let v of [void 0, null, 1, "", {}, [], () => {}]) {
      try {
        f(v);
      } catch (e) {
        assertSame(v, e);
        continue;
      }
      fail `expected error: ${v}`;
    }
  }

  let d = XPromise.deferred();
  d.promise.then()
           .then(testBuiltinFunctions)
           .catch(reportFailure);
  d.resolve(XPromise.resolve());
}
<|endoftext|>


<commit_before>/*! @source http://purl.eligrey.com/github/BlobBuilder.js/blob/master/BlobBuilder.js */
var BlobBuilder=BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||(function(j){"use strict";var c=function(v){return Object.prototype.toString.call(v).match(/^\[object\s(.*)\]$/)[1]},u=function(){this.data=[]},t=function(x,v,w){this.data=x;this.size=x.length;this.type=v;this.encoding=w},k=u.prototype,s=t.prototype,n=j.FileReaderSync,a=function(v){this.code=this[this.name=v]},l=("NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR").split(" "),r=l.length,o=j.URL||j.webkitURL||j,p=o.createObjectURL,b=o.revokeObjectURL,e=o,i=j.btoa,f=j.atob,m=false,h=function(v){m=!v},d=j.ArrayBuffer,g=j.Uint8Array;u.fake=s.fake=true;while(r--){a.prototype[l[r]]=r+1}try{if(g){h.apply(0,new g(1))}}catch(q){}if(!o.createObjectURL){e=j.URL={}}e.createObjectURL=function(w){var x=w.type,v;if(x===null){x="application/octet-stream"}if(w instanceof t){v="data:"+x;if(w.encoding==="base64"){return v+";base64,"+w.data}else{if(w.encoding==="URI"){return v+","+decodeURIComponent(w.data)}}if(i){return v+";base64,"+i(w.data)}else{return v+","+encodeURIComponent(w.data)}}else{if(real_create_object_url){return real_create_object_url.call(o,w)}}};e.revokeObjectURL=function(v){if(v.substring(0,5)!=="data:"&&real_revoke_object_url){real_revoke_object_url.call(o,v)}};k.append=function(z){var B=this.data;if(g&&z instanceof d){if(m){B.push(String.fromCharCode.apply(String,new g(z)))}else{var A="",w=new g(z),x=0,y=w.length;for(;x<y;x++){A+=String.fromCharCode(w[x])}}}else{if(c(z)==="Blob"||c(z)==="File"){if(n){var v=new n;B.push(v.readAsBinaryString(z))}else{throw new a("NOT_READABLE_ERR")}}else{if(z instanceof t){if(z.encoding==="base64"&&f){B.push(f(z.data))}else{if(z.encoding==="URI"){B.push(decodeURIComponent(z.data))}else{if(z.encoding==="raw"){B.push(z.data)}}}}else{if(typeof z!=="string"){z+=""}B.push(unescape(encodeURIComponent(z)))}}}};k.getBlob=function(v){if(!arguments.length){v=null}return new t(this.data.join(""),v,"raw")};k.toString=function(){return"[object BlobBuilder]"};s.slice=function(y,v,x){var w=arguments.length;if(w<3){x=null}return new t(this.data.slice(y,w>1?v:this.data.length),x,this.encoding)};s.toString=function(){return"[object Blob]"};return u}(self));<commit_msg>Removing BlobBuilder minified code, fixes #10<commit_after><|endoftext|>