<commit_before>/**
 * bootbox.js [v4.x/master branch]
 *
 * http://bootboxjs.com/license.txt
 */
// @see https://github.com/makeusabrew/bootbox/issues/71
window.bootbox = window.bootbox || (function(document, $, undefined) {
  "use strict";

  // the base DOM structure needed to create a modal
  var templates = {
    dialog:
      "
" +
        "
" +
          "
" +
            "
" +
              "

" +
            "
" +
            "

" +
            "

" +
          "
" +
        "
" +
      "
",
    closeButton:
      "<button type='button' class='bootbox-close-button close'>×</button>",
    form:
      "<form class='bootbox-form'></form>",
    inputs: {
      text:
        "<input class='bootbox-input input-block-level' autocomplete=off type=text />"
    }
  };

  // cache a reference to the jQueryfied body element
  var appendTo = $("body");

  var defaults = {
    // default language
    locale: "en",
    // show backdrop or not
    backdrop: true,
    // animate the modal in/out
    animate: true,
    // additional class string applied to the top level dialog
    className: null,
    // show the modal header or not
    header: true,
    // whether or not to include a close button, if a header is present
    closeButton: true,
    // show the dialog immediately by default
    show: true
  };

  // our public object; augmented after our private API
  var exports = {};

  /**
   * @private
   */
  function _t(key) {
    return locales[defaults.locale][key] || locales.en[key];
  }

  // @TODO inline within exports.dialog? closing over dialog & callbacks is neater...
  function processCallback(e, dialog, callback) {
    // by default we assume a callback will get rid of the dialog,
    // although they are given the opportunity to override this
    var preserveDialog = false;

    // so, if the callback can be invoked and it *explicitly returns false*
    // then we'll set a flag to keep the dialog active...
    if ($.isFunction(callback)) {
      preserveDialog = (callback(e) === false);
    }

    // ... otherwise we'll bin it
    if (!preserveDialog) {
      dialog.modal("hide");
    }
  }

  function sanitize(options) {
    var buttons = options.buttons;
    var total;
    var key;
    var keyIndex;
    var button;

    total = (function getKeyLength(obj) {
      // @TODO defer to Object.keys(x).length if available?
      var k, t = 0;
      for (k in obj) {
        t ++;
      }
      return t;
    }(buttons));

    if (typeof options !== "object") {
      throw new Error("Please supply an object of options");
    }

    if (!options.message) {
      throw new Error("Please specify a message");
    }

    // make sure any supplied options take precedence over defaults
    options = $.extend({}, defaults, options);

    if (!options.buttons) {
      options.buttons = {};
    }

    if (!options.title) {
      // @FIXME gah; we need to pad the header a bit...
      options.title = " ";
    }

    // we only support Bootstrap's "static" and false backdrop args
    // supporting true would mean you could dismiss the dialog without
    // explicitly interacting with it
    options.backdrop = options.backdrop ? "static" : false;

    keyIndex = 0;

    for (key in buttons) {
      keyIndex ++;

      button = buttons[key];

      if (!button.label) {
        throw new Error("Button with key " + key + " requires a label");
      }

      if (!button.className) {
        if (total <= 2 && keyIndex === total) {
          // always add a primary to the main option in a two-button dialog
          button.className = "btn-primary";
        } else {
          button.className = "btn-default";
        }
      }
    }

    return options;
  }

  function mapArguments(args, properties) {
    var argn = args.length;
    var options = {};

    if (argn < 1 || argn > 2) {
      throw new Error("Invalid argument length");
    }

    if (argn === 2 || typeof args[0] === "string") {
      options[properties[0]] = args[0];
      options[properties[1]] = args[1];
    } else {
      options = args[0];
    }

    return options;
  }

  function mergeArguments(defaults, args, properties) {
    return $.extend(true, {}, defaults, mapArguments(args, properties));
  }

  exports.alert = function() {
    var options;
    var defaults;

    defaults = {
      buttons: {
        ok: {
          label: _t("OK")
        }
      }
    };

    options = mergeArguments(defaults, arguments, ["message", "callback"]);

    /**
     * overrides
     */
    options.buttons.ok.callback = options.onEscape = function() {
      if ($.isFunction(options.callback)) {
        return options.callback();
      }
      return true;
    };

    return exports.dialog(options);
  };

  exports.confirm = function() {
    var options;
    var defaults;

    defaults = {
      buttons: {
        cancel: {
          label: _t("CANCEL")
        },
        confirm: {
          label: _t("CONFIRM")
        }
      }
    };

    options = mergeArguments(defaults, arguments, ["message", "callback"]);

    /**
     * overrides; undo anything the user tried to set they shouldn't have
     */
    options.buttons.cancel.callback = options.onEscape = function() {
      return options.callback(false);
    };

    options.buttons.confirm.callback = function() {
      return options.callback(true);
    };

    // confirm specific validation
    if (!$.isFunction(options.callback)) {
      throw new Error("Confirm method requires callback");
    }

    return exports.dialog(options);
  };

  exports.prompt = function() {
    var options;
    var defaults;
    var dialog;
    var form;
    var input;

    // we have to create our form first otherwise
    // its value is undefined when gearing up our options
    // @TODO this could be solved by allowing message to
    // be a function instead...
    form = $(templates.form);

    defaults = {
      buttons: {
        cancel: {
          label: _t("CANCEL")
        },
        confirm: {
          label: _t("CONFIRM")
        }
      },
      value: ""
    };

    options = mergeArguments(defaults, arguments, ["title", "callback"]);

    /**
     * overrides; undo anything the user tried to set they shouldn't have
     */
    options.message = form;

    options.buttons.cancel.callback = options.onEscape = function() {
      return options.callback(null);
    };

    options.buttons.confirm.callback = function() {
      return options.callback(input.val());
    };

    // prompt specific validation
    if (!options.title) {
      throw new Error("This method requires a title");
    }

    if (!$.isFunction(options.callback)) {
      throw new Error("This method requires a callback");
    }

    // create the input
    input = $(templates.inputs.text);
    input.val(options.value);

    // now place it in our form
    form.append(input);

    form.on("submit", function(e) {
      e.preventDefault();
      // @TODO can we actually click *the* button object instead?
      // e.g. buttons.confirm.click() or similar
      dialog.find(".btn-primary").click();
    });

    dialog = exports.dialog(options);

    // clear the existing handler focusing the submit button...
    dialog.off("shown.bs.modal");

    // ...and replace it with one focusing our input, if possible
    dialog.on("shown.bs.modal", function() {
      input.focus();
    });

    // @TODO this needs to respect whether the user asked for the dialog
    // to be shown or not, not just assumed...
    dialog.modal("show");

    return dialog;
  };

  exports.dialog = function(options) {
    options = sanitize(options);

    var dialog = $(templates.dialog);
    var buttons = options.buttons;
    var button;
    var key;
    var buttonStr = "";
    var callbacks = {
      // always assume an onEscape for now
      // @TODO make this optional
      // @TODO namespace this in case a user passes a button called 'escape'
      "escape": options.onEscape
    };

    // @TODO hasOwnProperty
    for (key in buttons) {
      button = buttons[key];

      // @TODO I don't like this string appending to itself; bit dirty. Needs reworking
      // can we just build up button elements instead? slower but neater. Then button
      // can just become a template too
      buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>";
      callbacks[key] = button.callback;
    }

    if (options.animate === true) {
      dialog.addClass("fade");
    }

    if (options.className) {
      dialog.addClass(options.className);
    }

    if (options.closeButton) {
      dialog.find(".modal-header").prepend(templates.closeButton);
    }

    if (options.title) {
      dialog.find(".modal-title").html(options.title);
    }

    // required bits last
    dialog.find(".modal-body").html(options.message);
    dialog.find(".modal-footer").html(buttonStr);

    /**
     * Bootstrap event listeners; used handle extra
     * setup & teardown required after the underlying
     * modal has performed certain actions
     */

    dialog.on("hidden.bs.modal", function(e) {
      // ensure we don't accidentally intercept hidden events triggered
      // by children of the current dialog. We shouldn't anymore now BS
      // namespaces its events; but still worth doing
      if (e.target === this) {
        dialog.remove();
      }
    });

    dialog.on("shown.bs.modal", function() {
      dialog.find(".btn-primary:first").focus();
    });

    /**
     * Bootbox event listeners; experimental and may not last
     * just an attempt to decouple some behaviours from their
     * respective triggers
     */

    dialog.on("escape.close.bb", function(e) {
      // @NOTE
      // if we declared processCallback locally we could take
      // advantage of our scope to just make the following...
      // processCallback(e, "escape");
      // and the one a bit further:
      // processCallback(e, $(this).data("bb-handler")
      // worth considering...
      processCallback(e, dialog, callbacks.escape);
    });

    /**
     * Standard jQuery event listeners; used to handle user
     * interaction with our dialog
     */

    dialog.on("click", ".modal-footer button", function(e) {
      e.preventDefault();

      var callbackKey = $(this).data("bb-handler");

      processCallback(e, dialog, callbacks[callbackKey]);

    });

    dialog.on("click", ".modal-header .close", function(e) {
      e.preventDefault();
      processCallback(e, dialog, callbacks.escape);
    });

    dialog.on("keyup", function(e) {
      // @TODO make conditional
      if (e.which === 27) {
        dialog.trigger("escape.close.bb");
      }
    });

    // the remainder of this method simply deals with adding our
    // dialogent to the DOM, augmenting it with Bootstrap's modal
    // functionality and then giving the resulting object back
    // to our caller

    appendTo.append(dialog);

    dialog.modal({
      backdrop: options.backdrop,
      keyboard: false,
      show: false
    });

    if (options.show) {
      dialog.modal("show");
    }

    // @TODO should we return the raw element here or should
    // we wrap it in an object on which we can expose some neater
    // methods, e.g. var d = bootbox.alert(); d.hide(); instead
    // of d.modal("hide");

   /*
    function BBDialog(elem) {
      this.elem = elem;
    }

    BBDialog.prototype = {
      hide: function() {
        return this.elem.modal("hide");
      },
      show: function() {
        return this.elem.modal("show");
      }
    };
    */

    return dialog;

  };

  exports.setDefaults = function(values) {
    $.extend(defaults, values);
  };

  exports.hideAll = function() {
    $(".bootbox").modal("hide");
  };

  /**
   * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are
   * unlikely to be required. If this gets too large it can be split out into separate JS files.
   */
  var locales = {
    br : {
      OK      : "OK",
      CANCEL  : "Cancelar",
      CONFIRM : "Sim"
    },
    da : {
      OK      : "OK",
      CANCEL  : "Annuller",
      CONFIRM : "Accepter"
    },
    de : {
      OK      : "OK",
      CANCEL  : "Abbrechen",
      CONFIRM : "Akzeptieren"
    },
    en : {
      OK      : "OK",
      CANCEL  : "Cancel",
      CONFIRM : "OK"
    },
    es : {
      OK      : "OK",
      CANCEL  : "Cancelar",
      CONFIRM : "Aceptar"
    },
    fi : {
      OK      : "OK",
      CANCEL  : "Peruuta",
      CONFIRM : "OK"
    },
    fr : {
      OK      : "OK",
      CANCEL  : "Annuler",
      CONFIRM : "D'accord"
    },
    it : {
      OK      : "OK",
      CANCEL  : "Annulla",
      CONFIRM : "Conferma"
    },
    nl : {
      OK      : "OK",
      CANCEL  : "Annuleren",
      CONFIRM : "Accepteren"
    },
    pl : {
      OK      : "OK",
      CANCEL  : "Anuluj",
      CONFIRM : "Potwierdź"
    },
    ru : {
      OK      : "OK",
      CANCEL  : "Отмена",
      CONFIRM : "Применить"
    },
    zh_CN : {
      OK      : "OK",
      CANCEL  : "取消",
      CONFIRM : "确认"
    },
    zh_TW : {
      OK      : "OK",
      CANCEL  : "取消",
      CONFIRM : "確認"
    }
  };

  return exports;

}(document, window.jQuery));
<commit_msg>add helper function to declare button labels<commit_after>/**
 * bootbox.js [v4.x/master branch]
 *
 * http://bootboxjs.com/license.txt
 */
// @see https://github.com/makeusabrew/bootbox/issues/71
window.bootbox = window.bootbox || (function(document, $, undefined) {
  "use strict";

  // the base DOM structure needed to create a modal
  var templates = {
    dialog:
      "
" +
        "
" +
          "
" +
            "
" +
              "

" +
            "
" +
            "

" +
            "

" +
          "
" +
        "
" +
      "
",
    closeButton:
      "<button type='button' class='bootbox-close-button close'>×</button>",
    form:
      "<form class='bootbox-form'></form>",
    inputs: {
      text:
        "<input class='bootbox-input input-block-level' autocomplete=off type=text />"
    }
  };

  // cache a reference to the jQueryfied body element
  var appendTo = $("body");

  var defaults = {
    // default language
    locale: "en",
    // show backdrop or not
    backdrop: true,
    // animate the modal in/out
    animate: true,
    // additional class string applied to the top level dialog
    className: null,
    // show the modal header or not
    header: true,
    // whether or not to include a close button, if a header is present
    closeButton: true,
    // show the dialog immediately by default
    show: true
  };

  // our public object; augmented after our private API
  var exports = {};

  /**
   * @private
   */
  function _t(key) {
    return locales[defaults.locale][key] || locales.en[key];
  }

  // @TODO inline within exports.dialog? closing over dialog & callbacks is neater...
  function processCallback(e, dialog, callback) {
    // by default we assume a callback will get rid of the dialog,
    // although they are given the opportunity to override this
    var preserveDialog = false;

    // so, if the callback can be invoked and it *explicitly returns false*
    // then we'll set a flag to keep the dialog active...
    if ($.isFunction(callback)) {
      preserveDialog = (callback(e) === false);
    }

    // ... otherwise we'll bin it
    if (!preserveDialog) {
      dialog.modal("hide");
    }
  }

  function sanitize(options) {
    var buttons = options.buttons;
    var total;
    var key;
    var keyIndex;
    var button;

    total = (function getKeyLength(obj) {
      // @TODO defer to Object.keys(x).length if available?
      var k, t = 0;
      for (k in obj) {
        t ++;
      }
      return t;
    }(buttons));

    if (typeof options !== "object") {
      throw new Error("Please supply an object of options");
    }

    if (!options.message) {
      throw new Error("Please specify a message");
    }

    // make sure any supplied options take precedence over defaults
    options = $.extend({}, defaults, options);

    if (!options.buttons) {
      options.buttons = {};
    }

    if (!options.title) {
      // @FIXME gah; we need to pad the header a bit...
      options.title = " ";
    }

    // we only support Bootstrap's "static" and false backdrop args
    // supporting true would mean you could dismiss the dialog without
    // explicitly interacting with it
    options.backdrop = options.backdrop ? "static" : false;

    keyIndex = 0;

    for (key in buttons) {
      keyIndex ++;

      button = buttons[key];

      if (!button.label) {
        throw new Error("Button with key " + key + " requires a label");
      }

      if (!button.className) {
        if (total <= 2 && keyIndex === total) {
          // always add a primary to the main option in a two-button dialog
          button.className = "btn-primary";
        } else {
          button.className = "btn-default";
        }
      }
    }

    return options;
  }

  function mapArguments(args, properties) {
    var argn = args.length;
    var options = {};

    if (argn < 1 || argn > 2) {
      throw new Error("Invalid argument length");
    }

    if (argn === 2 || typeof args[0] === "string") {
      options[properties[0]] = args[0];
      options[properties[1]] = args[1];
    } else {
      options = args[0];
    }

    return options;
  }

  function mergeArguments(defaults, args, properties) {
    return $.extend(true, {}, defaults, mapArguments(args, properties));
  }

  function buttonLabels() {
    var buttons = {};

    for (var i = 0, j = arguments.length; i < j; i++) {
      var argument = arguments[i];
      var key = argument.toLowerCase();
      var value = argument.toUpperCase();

      buttons[key] = {
        label: _t(value)
      };
    }

    return buttons;
  }

  exports.alert = function() {
    var options;
    var defaults;

    defaults = {
      buttons: buttonLabels("ok")
    };

    options = mergeArguments(defaults, arguments, ["message", "callback"]);

    /**
     * overrides
     */
    options.buttons.ok.callback = options.onEscape = function() {
      if ($.isFunction(options.callback)) {
        return options.callback();
      }
      return true;
    };

    return exports.dialog(options);
  };

  exports.confirm = function() {
    var options;
    var defaults;

    defaults = {
      buttons: buttonLabels("cancel", "confirm")
    };

    options = mergeArguments(defaults, arguments, ["message", "callback"]);

    /**
     * overrides; undo anything the user tried to set they shouldn't have
     */
    options.buttons.cancel.callback = options.onEscape = function() {
      return options.callback(false);
    };

    options.buttons.confirm.callback = function() {
      return options.callback(true);
    };

    // confirm specific validation
    if (!$.isFunction(options.callback)) {
      throw new Error("Confirm method requires callback");
    }

    return exports.dialog(options);
  };

  exports.prompt = function() {
    var options;
    var defaults;
    var dialog;
    var form;
    var input;

    // we have to create our form first otherwise
    // its value is undefined when gearing up our options
    // @TODO this could be solved by allowing message to
    // be a function instead...
    form = $(templates.form);

    defaults = {
      buttons: buttonLabels("cancel", "confirm"),
      value: ""
    };

    options = mergeArguments(defaults, arguments, ["title", "callback"]);

    /**
     * overrides; undo anything the user tried to set they shouldn't have
     */
    options.message = form;

    options.buttons.cancel.callback = options.onEscape = function() {
      return options.callback(null);
    };

    options.buttons.confirm.callback = function() {
      return options.callback(input.val());
    };

    // prompt specific validation
    if (!options.title) {
      throw new Error("This method requires a title");
    }

    if (!$.isFunction(options.callback)) {
      throw new Error("This method requires a callback");
    }

    // create the input
    input = $(templates.inputs.text);
    input.val(options.value);

    // now place it in our form
    form.append(input);

    form.on("submit", function(e) {
      e.preventDefault();
      // @TODO can we actually click *the* button object instead?
      // e.g. buttons.confirm.click() or similar
      dialog.find(".btn-primary").click();
    });

    dialog = exports.dialog(options);

    // clear the existing handler focusing the submit button...
    dialog.off("shown.bs.modal");

    // ...and replace it with one focusing our input, if possible
    dialog.on("shown.bs.modal", function() {
      input.focus();
    });

    // @TODO this needs to respect whether the user asked for the dialog
    // to be shown or not, not just assumed...
    dialog.modal("show");

    return dialog;
  };

  exports.dialog = function(options) {
    options = sanitize(options);

    var dialog = $(templates.dialog);
    var buttons = options.buttons;
    var button;
    var key;
    var buttonStr = "";
    var callbacks = {
      // always assume an onEscape for now
      // @TODO make this optional
      // @TODO namespace this in case a user passes a button called 'escape'
      "escape": options.onEscape
    };

    // @TODO hasOwnProperty
    for (key in buttons) {
      button = buttons[key];

      // @TODO I don't like this string appending to itself; bit dirty. Needs reworking
      // can we just build up button elements instead? slower but neater. Then button
      // can just become a template too
      buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>";
      callbacks[key] = button.callback;
    }

    if (options.animate === true) {
      dialog.addClass("fade");
    }

    if (options.className) {
      dialog.addClass(options.className);
    }

    if (options.closeButton) {
      dialog.find(".modal-header").prepend(templates.closeButton);
    }

    if (options.title) {
      dialog.find(".modal-title").html(options.title);
    }

    // required bits last
    dialog.find(".modal-body").html(options.message);
    dialog.find(".modal-footer").html(buttonStr);

    /**
     * Bootstrap event listeners; used handle extra
     * setup & teardown required after the underlying
     * modal has performed certain actions
     */

    dialog.on("hidden.bs.modal", function(e) {
      // ensure we don't accidentally intercept hidden events triggered
      // by children of the current dialog. We shouldn't anymore now BS
      // namespaces its events; but still worth doing
      if (e.target === this) {
        dialog.remove();
      }
    });

    dialog.on("shown.bs.modal", function() {
      dialog.find(".btn-primary:first").focus();
    });

    /**
     * Bootbox event listeners; experimental and may not last
     * just an attempt to decouple some behaviours from their
     * respective triggers
     */

    dialog.on("escape.close.bb", function(e) {
      // @NOTE
      // if we declared processCallback locally we could take
      // advantage of our scope to just make the following...
      // processCallback(e, "escape");
      // and the one a bit further:
      // processCallback(e, $(this).data("bb-handler")
      // worth considering...
      processCallback(e, dialog, callbacks.escape);
    });

    /**
     * Standard jQuery event listeners; used to handle user
     * interaction with our dialog
     */

    dialog.on("click", ".modal-footer button", function(e) {
      e.preventDefault();

      var callbackKey = $(this).data("bb-handler");

      processCallback(e, dialog, callbacks[callbackKey]);

    });

    dialog.on("click", ".modal-header .close", function(e) {
      e.preventDefault();
      processCallback(e, dialog, callbacks.escape);
    });

    dialog.on("keyup", function(e) {
      // @TODO make conditional
      if (e.which === 27) {
        dialog.trigger("escape.close.bb");
      }
    });

    // the remainder of this method simply deals with adding our
    // dialogent to the DOM, augmenting it with Bootstrap's modal
    // functionality and then giving the resulting object back
    // to our caller

    appendTo.append(dialog);

    dialog.modal({
      backdrop: options.backdrop,
      keyboard: false,
      show: false
    });

    if (options.show) {
      dialog.modal("show");
    }

    // @TODO should we return the raw element here or should
    // we wrap it in an object on which we can expose some neater
    // methods, e.g. var d = bootbox.alert(); d.hide(); instead
    // of d.modal("hide");

   /*
    function BBDialog(elem) {
      this.elem = elem;
    }

    BBDialog.prototype = {
      hide: function() {
        return this.elem.modal("hide");
      },
      show: function() {
        return this.elem.modal("show");
      }
    };
    */

    return dialog;

  };

  exports.setDefaults = function(values) {
    $.extend(defaults, values);
  };

  exports.hideAll = function() {
    $(".bootbox").modal("hide");
  };

  /**
   * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are
   * unlikely to be required. If this gets too large it can be split out into separate JS files.
   */
  var locales = {
    br : {
      OK      : "OK",
      CANCEL  : "Cancelar",
      CONFIRM : "Sim"
    },
    da : {
      OK      : "OK",
      CANCEL  : "Annuller",
      CONFIRM : "Accepter"
    },
    de : {
      OK      : "OK",
      CANCEL  : "Abbrechen",
      CONFIRM : "Akzeptieren"
    },
    en : {
      OK      : "OK",
      CANCEL  : "Cancel",
      CONFIRM : "OK"
    },
    es : {
      OK      : "OK",
      CANCEL  : "Cancelar",
      CONFIRM : "Aceptar"
    },
    fi : {
      OK      : "OK",
      CANCEL  : "Peruuta",
      CONFIRM : "OK"
    },
    fr : {
      OK      : "OK",
      CANCEL  : "Annuler",
      CONFIRM : "D'accord"
    },
    it : {
      OK      : "OK",
      CANCEL  : "Annulla",
      CONFIRM : "Conferma"
    },
    nl : {
      OK      : "OK",
      CANCEL  : "Annuleren",
      CONFIRM : "Accepteren"
    },
    pl : {
      OK      : "OK",
      CANCEL  : "Anuluj",
      CONFIRM : "Potwierdź"
    },
    ru : {
      OK      : "OK",
      CANCEL  : "Отмена",
      CONFIRM : "Применить"
    },
    zh_CN : {
      OK      : "OK",
      CANCEL  : "取消",
      CONFIRM : "确认"
    },
    zh_TW : {
      OK      : "OK",
      CANCEL  : "取消",
      CONFIRM : "確認"
    }
  };

  return exports;

}(document, window.jQuery));
<|endoftext|>


<commit_before>/**

*/

define(
	[
		'jsorrery/NameSpace',
		'jquery',
		'jsorrery/CelestialBody',
		'jsorrery/algorithm/Ticker',
		'jsorrery/graphics3d/Scene',
		'jsorrery/gui/Gui',
		'jsorrery/graphics2d/Labels',
		'jsorrery/graphics3d/loaders/ResourceLoader',
		'_'
	],
	function(ns, $, CelestialBody, Ticker, Scene, Gui, Labels, ResourceLoader) {
		'use strict';
		var Universe = {
			init : function(scenario, qstrSettings){
				ResourceLoader.reset();
				this.name = scenario.name;
				var initialSettings = _.extend({}, scenario.defaultGuiSettings, qstrSettings, scenario.forcedGuiSettings);
				//console.log(initialSettings);
				Gui.setDefaults(initialSettings);
				//Universe is, well, global
				ns.U = this;

				this.usePhysics = scenario.usePhysics || ns.USE_PHYSICS_BY_DEFAULT;

				Labels.init();

				//start/stop
				Gui.addBtn('play', Gui.START_ID, function(){
					this.playing = !this.playing;
				}.bind(this));

				this.dateDisplay = Gui.addDate(function(){
					this.playing = false;
					this.epochTime = 0;
					this.currentTime = this.startEpochTime = this.getEpochTime(Gui.getDate());
					this.repositionBodies();
					this.scene.onDateReset();
				}.bind(this));

				this.ticker = this.tick.bind(this);

				this.deltaT = scenario.secondsPerTick;
				this.playing = false;
				this.epochTime = 0;

				this.date = Gui.getDate() || new Date();
				this.currentTime = this.startEpochTime = this.getEpochTime(this.date);

				this.createBodies(scenario);

				this.scene = Object.create(Scene);
				this.calculateDimensions();
				this.scene.createStage(scenario);

				this.initBodies(scenario);
				this.scene.setCentralBody(this.centralBody);
				Ticker.setSecondsPerTick(scenario.secondsPerTick);
				Ticker.setCalculationsPerTick(scenario.calculationsPerTick || ns.defaultCalculationsPerTick);
				var onSceneReady = ResourceLoader.getOnReady();

				onSceneReady.done(function(){
					this.showDate();
					Gui.putDefaults();
					this.scene.setCameraDefaults(initialSettings.cameraSettings);
					this.scene.draw();
					this.tick();
				}.bind(this));

				return onSceneReady.promise();

			},

			kill : function(){
				//kills the animation callback
				this.killed = true;
				this.dateDisplay.off('.jsorrery');
				Gui.setDate(null);
				if(!this.scene) return;
				this.scene.kill();
				this.centralBody = null;
				this.scene = null;
				this.bodies = {};

				Labels.kill();
			},

			createBodies : function(scenario) {
				var bodies = [];
				this.bodies = {};

				$.each(scenario.bodies, function(name, config){
					var body = Object.create(CelestialBody);
					$.extend(body, config);
					body.name = name;
					this.centralBody = this.centralBody && this.centralBody.mass > body.mass ? this.centralBody : body;
					this.bodies[body.name] = body;

					bodies.push(body);
				}.bind(this));

				this.centralBody.isCentral = true;

			},

			initBodies : function(scenario){

				$.each(this.bodies, function(name, body){
					if((typeof scenario.calculateAll === 'undefined' || !scenario.calculateAll) && !body.isCentral){
						body.mass = 1;
					}
					body.init();
					body.setPositionFromDate(this.currentTime, true);

				}.bind(this));

				//after all is inialized
				$.each(this.bodies, function(name, body){
					this.scene.addBody(body);
					body.afterInitialized();
					//console.log(body.name, body.isCentral);
				}.bind(this));

				Ticker.setBodies(this.bodies);
			},

			repositionBodies : function(){
				$.each(this.bodies, function(name, body){
					body.reset();
					body.setPositionFromDate(this.currentTime, true);
				}.bind(this));
				//adjust position depending on other bodies' position (for example a satellite is relative to its main body)
				$.each(this.bodies, function(name, body){
					body.afterInitialized();
				}.bind(this));
			},

			getBody : function(name) {
				if(name === 'central' || !name) {
					return this.centralBody;
				}
				return this.bodies[name];
			},

			calculateDimensions : function(){
				var centralBodyName = this.getBody().name;
				//find the largest radius in km among all bodies
				var largestRadius = _.reduce(this.bodies, function(memo, body){
					return memo < body.radius ? body.radius : memo;
				}, 0);
				//find the largest semi major axis in km among all bodies
				var largestSMA = _.reduce(this.bodies, function(memo, body){
					return (!body.isCentral && body.orbit && body.orbit.base.a > memo) ? body.orbit.base.a : memo;
				}, 0);
				var smallestSMA = _.reduce(this.bodies, function(memo, body){
					return (!body.isCentral && body.orbit && (!body.relativeTo || body.relativeTo == centralBodyName) && (!memo || body.orbit.base.a < memo)) ? body.orbit.base.a : memo;
				}, 0);
				smallestSMA *= ns.KM;
				largestSMA *= ns.KM;
				largestRadius *= ns.KM;

				//console.log('universe size', largestSMA, ' m');

				this.size = largestSMA;
				this.scene.setDimension(largestSMA, smallestSMA, largestRadius);

			},

			showDate : function(){
				this.date.setTime(ns.J2000.getTime() + (this.currentTime * 1000));
				Gui.setDate(this.date);
			},

			tick : function() {
				if(this.killed) return;
				if(this.playing) {

					this.epochTime += this.deltaT;
					this.currentTime = this.startEpochTime + this.epochTime;
					Ticker.tick(this.usePhysics, this.currentTime);

					this.scene.updateCamera();
					this.scene.draw();
					this.showDate();
				} else {
					this.scene.updateCamera();
				}

				requestAnimFrame(this.ticker);
			},

			getEpochTime : function(userDate) {
				userDate = userDate || new Date();
				return ((userDate - ns.J2000) / 1000) ;
			},

			isPlaying : function() {
				return this.playing;
			},

			stop : function(){
				this.playing = false;
				this.scene.updateCamera();
				this.scene.draw();
			}
		};
		return Universe;

	}
);

/**
 * Provides requestAnimationFrame in a cross browser way.
 * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
 */

// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame    ||
          window.oRequestAnimationFrame      ||
          window.msRequestAnimationFrame     ||
          function(/* function */ callback, /* DOMElement */ element){
            window.setTimeout(callback, 1000 / 60);
          };
})();<commit_msg>tick after manually reposition bodies<commit_after>/**

*/

define(
	[
		'jsorrery/NameSpace',
		'jquery',
		'jsorrery/CelestialBody',
		'jsorrery/algorithm/Ticker',
		'jsorrery/graphics3d/Scene',
		'jsorrery/gui/Gui',
		'jsorrery/graphics2d/Labels',
		'jsorrery/graphics3d/loaders/ResourceLoader',
		'_'
	],
	function(ns, $, CelestialBody, Ticker, Scene, Gui, Labels, ResourceLoader) {
		'use strict';
		var Universe = {
			init : function(scenario, qstrSettings){
				ResourceLoader.reset();
				this.name = scenario.name;
				var initialSettings = _.extend({}, scenario.defaultGuiSettings, qstrSettings, scenario.forcedGuiSettings);
				//console.log(initialSettings);
				Gui.setDefaults(initialSettings);
				//Universe is, well, global
				ns.U = this;

				this.usePhysics = scenario.usePhysics || ns.USE_PHYSICS_BY_DEFAULT;

				Labels.init();

				//start/stop
				Gui.addBtn('play', Gui.START_ID, function(){
					this.playing = !this.playing;
				}.bind(this));

				this.dateDisplay = Gui.addDate(function(){
					this.playing = false;
					this.epochTime = 0;
					this.currentTime = this.startEpochTime = this.getEpochTime(Gui.getDate());
					this.repositionBodies();
					this.scene.onDateReset();
				}.bind(this));

				this.ticker = this.tick.bind(this);

				this.deltaT = scenario.secondsPerTick;
				this.playing = false;
				this.epochTime = 0;

				this.date = Gui.getDate() || new Date();
				this.currentTime = this.startEpochTime = this.getEpochTime(this.date);

				this.createBodies(scenario);

				this.scene = Object.create(Scene);
				this.calculateDimensions();
				this.scene.createStage(scenario);

				this.initBodies(scenario);
				this.scene.setCentralBody(this.centralBody);
				Ticker.setSecondsPerTick(scenario.secondsPerTick);
				Ticker.setCalculationsPerTick(scenario.calculationsPerTick || ns.defaultCalculationsPerTick);
				var onSceneReady = ResourceLoader.getOnReady();

				onSceneReady.done(function(){
					this.showDate();
					Gui.putDefaults();
					this.scene.setCameraDefaults(initialSettings.cameraSettings);
					this.scene.draw();
					this.tick();
				}.bind(this));

				return onSceneReady.promise();

			},

			kill : function(){
				//kills the animation callback
				this.killed = true;
				this.dateDisplay.off('.jsorrery');
				Gui.setDate(null);
				if(!this.scene) return;
				this.scene.kill();
				this.centralBody = null;
				this.scene = null;
				this.bodies = {};

				Labels.kill();
			},

			createBodies : function(scenario) {
				var bodies = [];
				this.bodies = {};

				$.each(scenario.bodies, function(name, config){
					var body = Object.create(CelestialBody);
					$.extend(body, config);
					body.name = name;
					this.centralBody = this.centralBody && this.centralBody.mass > body.mass ? this.centralBody : body;
					this.bodies[body.name] = body;

					bodies.push(body);
				}.bind(this));

				this.centralBody.isCentral = true;

			},

			initBodies : function(scenario){

				$.each(this.bodies, function(name, body){
					if((typeof scenario.calculateAll === 'undefined' || !scenario.calculateAll) && !body.isCentral){
						body.mass = 1;
					}
					body.init();
					body.setPositionFromDate(this.currentTime, true);

				}.bind(this));

				//after all is inialized
				$.each(this.bodies, function(name, body){
					this.scene.addBody(body);
					body.afterInitialized();
					//console.log(body.name, body.isCentral);
				}.bind(this));

				Ticker.setBodies(this.bodies);
			},

			repositionBodies : function(){
				$.each(this.bodies, function(name, body){
					body.reset();
					body.setPositionFromDate(this.currentTime, true);
				}.bind(this));

				Ticker.tick(false, this.currentTime);

				//adjust position depending on other bodies' position (for example a satellite is relative to its main body)
				$.each(this.bodies, function(name, body){
					body.afterInitialized();
				}.bind(this));
			},

			getBody : function(name) {
				if(name === 'central' || !name) {
					return this.centralBody;
				}
				return this.bodies[name];
			},

			calculateDimensions : function(){
				var centralBodyName = this.getBody().name;
				//find the largest radius in km among all bodies
				var largestRadius = _.reduce(this.bodies, function(memo, body){
					return memo < body.radius ? body.radius : memo;
				}, 0);
				//find the largest semi major axis in km among all bodies
				var largestSMA = _.reduce(this.bodies, function(memo, body){
					return (!body.isCentral && body.orbit && body.orbit.base.a > memo) ? body.orbit.base.a : memo;
				}, 0);
				var smallestSMA = _.reduce(this.bodies, function(memo, body){
					return (!body.isCentral && body.orbit && (!body.relativeTo || body.relativeTo == centralBodyName) && (!memo || body.orbit.base.a < memo)) ? body.orbit.base.a : memo;
				}, 0);
				smallestSMA *= ns.KM;
				largestSMA *= ns.KM;
				largestRadius *= ns.KM;

				//console.log('universe size', largestSMA, ' m');

				this.size = largestSMA;
				this.scene.setDimension(largestSMA, smallestSMA, largestRadius);

			},

			showDate : function(){
				this.date.setTime(ns.J2000.getTime() + (this.currentTime * 1000));
				Gui.setDate(this.date);
			},

			tick : function() {
				if(this.killed) return;
				if(this.playing) {

					this.epochTime += this.deltaT;
					this.currentTime = this.startEpochTime + this.epochTime;
					Ticker.tick(this.usePhysics, this.currentTime);

					this.scene.updateCamera();
					this.scene.draw();
					this.showDate();
				} else {
					this.scene.updateCamera();
				}

				requestAnimFrame(this.ticker);
			},

			getEpochTime : function(userDate) {
				userDate = userDate || new Date();
				return ((userDate - ns.J2000) / 1000) ;
			},

			isPlaying : function() {
				return this.playing;
			},

			stop : function(){
				this.playing = false;
				this.scene.updateCamera();
				this.scene.draw();
			}
		};
		return Universe;

	}
);

/**
 * Provides requestAnimationFrame in a cross browser way.
 * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
 */

// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame    ||
          window.oRequestAnimationFrame      ||
          window.msRequestAnimationFrame     ||
          function(/* function */ callback, /* DOMElement */ element){
            window.setTimeout(callback, 1000 / 60);
          };
})();<|endoftext|>


<commit_before>
var presetUsers = ['Doug','Dylan','Sean','Kaylyn','Sam','Nick','Brian','Nadia'];
var bestMatch = '';
var bestMatchPic = '';
var allUsersObjectArray = [];
var allUsersObjectArrayOrdered = [];
var top3BroNachosObjArray = [];
var bottom3BroNachosObjArray = [];
var allToppingsArray = [];
var userSelectedArray = [];
var ingredientsArray = ['rice', 'beans', 'chicken', 'onions', 'jalapenos', 'corn', 'salsa', 'sourCream', 'guac', 'olives', 'cilantro', 'beer'];

// assemble ingredient objects and add event listeners
function addIngredients () {
  for(var i = 0; i < ingredientsArray.length; i++) {
    var currentIngredient = document.getElementById(ingredientsArray[i]);
    allToppingsArray.push(currentIngredient);
    document.getElementById(ingredientsArray[i] + 'Photo').addEventListener('click', turnGreen);
  };
};
addIngredients();

function NachoBuilder(userName, filePath, allToppingsArray) {
  this.userName = userName;
  this.filePath = filePath;
  for(var i = 0; i < ingredientsArray.length; i++) {
    this[ingredientsArray[i]] = allToppingsArray[i];
  }

  allUsersObjectArray.push(this);
  this.userToppingsArray = allToppingsArray;
  this.matchesWithNewUser = 0;
}

Doug = new NachoBuilder('Doug','../imgs/profile-imgs/doug.jpg',[true,false,false,false,true,false,false,true,true,false,true,false]);
Dylan = new NachoBuilder('Dylan','../imgs/profile-imgs/dylan.jpeg',[false,true,false,false,true,true,false,false,true,true,false,false]);
Sean = new NachoBuilder('Sean','../imgs/profile-imgs/sean.jpg',[false,false,true,false,true,true,false,false,false,true,true,false]);
Kaylyn = new NachoBuilder('Kaylyn','../imgs/profile-imgs/kaylyn.jpeg',[false,false,false,true,false,false,false,true,false,true,true,true]);
Sam = new NachoBuilder('Sam','../imgs/profile-imgs/sam.jpeg',[true,true,true,true,false,false,false,false,true,true,true,false]);
Nick = new NachoBuilder('Nick','../imgs/profile-imgs/nick.jpg',[false,true,true,false,true,true,true,false,false,true,false,true]);
Brian = new NachoBuilder('Brian','../imgs/profile-imgs/brian.jpg',[false,false,true,true,false,true,true,false,false,false,false,false]);
Nadia = new NachoBuilder('Nadia','../imgs/profile-imgs/nadia.jpg',[true,false,true,false,true,false,false,true,true,true,false,false]);

var form = document.getElementById('nachoForm');
form.addEventListener('submit', startBroNacho);

var userName = document.getElementById('userNameInput');
var updateList = document.getElementById('ingredientListInBuilder');

function turnGreen() {
  if (this.className === 'inactive') {
    this.className = 'active';
    var alt = document.getElementById(this.alt);
    alt.checked = true;
    userSelectedArray.push(alt);
    removeHidden();
    updateList.innerHTML = '';
    for (var i = 0; i < userSelectedArray.length; i++) {
      var liEl = document.createElement('li');
      liEl.textContent = userSelectedArray[i].value;
      updateList.appendChild(liEl);
    }
    console.log(this.alt + ' has been selected');
  } else {
    this.className = 'inactive';
    document.getElementById(this.alt).checked = false;
    for (var i = 0; i < userSelectedArray.length; i++) {
      if(this.alt === userSelectedArray[i].value) {
        userSelectedArray.splice(i,1);
      }
    }
    updateList.innerHTML = '';
    for (var i = 0; i < userSelectedArray.length; i++) {
      var liEl = document.createElement('li');
      liEl.textContent = userSelectedArray[i].value;
      updateList.appendChild(liEl);
    }
    console.log(this.alt + ' has been unchecked');
  }
  buttonAppear();
}
function buttonAppear () {
  if (userSelectedArray.length > 4)  {
    var submitButton = document.getElementById('submitButton');
    submitButton.className = '';
  }
}

function removeHidden() {
  var endOfList = document.getElementById('endOfSelectedIngredients');
  updateList.className = '';
  endOfList.className = '';
}

function removeFromPreviewFooter() {
  updateList.removeChild('liEl');
}

function startBroNacho() {
  event.preventDefault();

  newUser = new NachoBuilder(userName.value,'', allToppingsArray);

  compareToEachUser();
  console.log(bestMatch + ' is your BroNacho');
  document.getElementById('broNachoPic').setAttribute('src', bestMatchPic);
  var elP = document.getElementById('broNachoOutput');
  elP.textContent = bestMatch + ' is your BroNacho';

  localStorage.setItem('top3BroNachos',JSON.stringify(top3BroNachosObjArray));
  localStorage.setItem('bottom3BroNachos',JSON.stringify(bottom3BroNachosObjArray));
  localStorage.setItem('allUsers',JSON.stringify(allUsersObjectArrayOrdered));

  window.open('../html/results.html');

// console log all scores
  for( var i = 0; i < allUsersObjectArrayOrdered.length - 1; i++){
    console.log(allUsersObjectArrayOrdered[i].userName + ' ' + allUsersObjectArrayOrdered[i].matchesWithNewUser);
  }
}

function compareToEachUser() {

  var last = allUsersObjectArray.length - 1;
  var counter = 0;

  for(var i = 0; i < allUsersObjectArray.length - 1; i++) {
    for(var j = 0; j < allUsersObjectArray[i].userToppingsArray.length; j++) {
      if(allUsersObjectArray[i].userToppingsArray[j] === allUsersObjectArray[last].userToppingsArray[j] && (allUsersObjectArray[last].userToppingsArray[j] === true)) {
        counter = counter + 2;
      }
      if(allUsersObjectArray[i].userToppingsArray[j] === allUsersObjectArray[last].userToppingsArray[j] && (allUsersObjectArray[last].userToppingsArray[j] === false)) {
        counter = counter + 1;
      }
    }
    allUsersObjectArray[i].matchesWithNewUser = counter;
    counter = 0;
  }

  findBestMatch();
}

function findBestMatch() {

  allUsersObjectArrayOrdered = allUsersObjectArrayOrdered.concat(allUsersObjectArray);

  for(var f = 0; f < (allUsersObjectArrayOrdered.length - 2); f++) {
    var g = f + 1;
    if(allUsersObjectArrayOrdered[g].matchesWithNewUser > allUsersObjectArrayOrdered[f].matchesWithNewUser) {
      var toFront = allUsersObjectArrayOrdered[g];
      allUsersObjectArrayOrdered.splice(g,1);
      allUsersObjectArrayOrdered.unshift(toFront);
      f = -1;
    }
  }

  var last = allUsersObjectArrayOrdered.length - 2;

  bestMatch = allUsersObjectArrayOrdered[0].userName;
  bestMatchPic = allUsersObjectArrayOrdered[0].filePath;
  top3BroNachosObjArray = [allUsersObjectArrayOrdered[0],allUsersObjectArrayOrdered[1],allUsersObjectArrayOrdered[2]];
  bottom3BroNachosObjArray = [allUsersObjectArrayOrdered[last],allUsersObjectArrayOrdered[last - 1],allUsersObjectArrayOrdered[last - 2]];
  return bestMatch;
}
<commit_msg>update user array T/F<commit_after>
var presetUsers = ['Doug','Dylan','Sean','Kaylyn','Sam','Nick','Brian','Nadia'];
var bestMatch = '';
var bestMatchPic = '';
var allUsersObjectArray = [];
var allUsersObjectArrayOrdered = [];
var top3BroNachosObjArray = [];
var bottom3BroNachosObjArray = [];
var allToppingsArray = [];
var userSelectedArray = [];
var newUserToppingsArray = [];
var ingredientsArray = ['rice', 'beans', 'chicken', 'onions', 'jalapenos', 'corn', 'salsa', 'sourCream', 'guac', 'olives', 'cilantro', 'beer'];

// assemble ingredient objects and add event listeners
function addIngredients () {
  for(var i = 0; i < ingredientsArray.length; i++) {
    var currentIngredient = document.getElementById(ingredientsArray[i]);
    allToppingsArray.push(currentIngredient);
    document.getElementById(ingredientsArray[i] + 'Photo').addEventListener('click', turnGreen);
  };
};
addIngredients();

function NachoBuilder(userName, filePath, allToppingsArray) {
  this.userName = userName;
  this.filePath = filePath;
  for(var i = 0; i < ingredientsArray.length; i++) {
    this[ingredientsArray[i]] = allToppingsArray[i];
  }

  allUsersObjectArray.push(this);
  this.userToppingsArray = allToppingsArray;
  this.matchesWithNewUser = 0;
}

Doug = new NachoBuilder('Doug','../imgs/profile-imgs/doug.jpg',[true,false,false,false,true,false,false,true,true,false,true,false]);
Dylan = new NachoBuilder('Dylan','../imgs/profile-imgs/dylan.jpeg',[false,true,false,false,true,true,false,false,true,true,false,false]);
Sean = new NachoBuilder('Sean','../imgs/profile-imgs/sean.jpg',[false,false,true,false,true,true,false,false,false,true,true,false]);
Kaylyn = new NachoBuilder('Kaylyn','../imgs/profile-imgs/kaylyn.jpeg',[false,false,false,true,false,false,false,true,false,true,true,true]);
Sam = new NachoBuilder('Sam','../imgs/profile-imgs/sam.jpeg',[true,true,true,true,false,false,false,false,true,true,true,false]);
Nick = new NachoBuilder('Nick','../imgs/profile-imgs/nick.jpg',[false,true,true,false,true,true,true,false,false,true,false,true]);
Brian = new NachoBuilder('Brian','../imgs/profile-imgs/brian.jpg',[false,false,true,true,false,true,true,false,false,false,false,false]);
Nadia = new NachoBuilder('Nadia','../imgs/profile-imgs/nadia.jpg',[true,false,true,false,true,false,false,true,true,true,false,false]);

var form = document.getElementById('nachoForm');
form.addEventListener('submit', startBroNacho);

var userName = document.getElementById('userNameInput');
var updateList = document.getElementById('ingredientListInBuilder');

function turnGreen() {
  if (this.className === 'inactive') {
    this.className = 'active';
    var alt = document.getElementById(this.alt);
    alt.checked = true;
    userSelectedArray.push(alt);
    removeHidden();
    updateList.innerHTML = '';
    for (var i = 0; i < userSelectedArray.length; i++) {
      var liEl = document.createElement('li');
      liEl.textContent = userSelectedArray[i].value;
      updateList.appendChild(liEl);
    }
    console.log(this.alt + ' has been selected');
  } else {
    this.className = 'inactive';
    document.getElementById(this.alt).checked = false;
    for (var i = 0; i < userSelectedArray.length; i++) {
      if(this.alt === userSelectedArray[i].value) {
        userSelectedArray.splice(i,1);
      }
    }
    updateList.innerHTML = '';
    for (var i = 0; i < userSelectedArray.length; i++) {
      var liEl = document.createElement('li');
      liEl.textContent = userSelectedArray[i].value;
      updateList.appendChild(liEl);
    }
    console.log(this.alt + ' has been unchecked');
  }
  buttonAppear();
}
function buttonAppear () {
  if (userSelectedArray.length > 4) {
    var submitButton = document.getElementById('submitButton');
    submitButton.className = '';
  }
}

function removeHidden() {
  var endOfList = document.getElementById('endOfSelectedIngredients');
  updateList.className = '';
  endOfList.className = '';
}

function removeFromPreviewFooter() {
  updateList.removeChild('liEl');
}

function setupNewUser() {
  for (var i = 0; i < ingredientsArray.length; i++) {
    for (j = 0; j < userSelectedArray.length; j++) {
      if(ingredientsArray[i] === userSelectedArray[j].value) {
        newUserToppingsArray[i] = true;
        break;
      } else {
        newUserToppingsArray[i] = false;
      }
    }
  }
}

function startBroNacho() {
  event.preventDefault();

  setupNewUser();
  console.log(newUserToppingsArray);
  newUser = new NachoBuilder(userName.value,'', newUserToppingsArray);

  compareToEachUser();
  console.log(bestMatch + ' is your BroNacho');
  document.getElementById('broNachoPic').setAttribute('src', bestMatchPic);
  var elP = document.getElementById('broNachoOutput');
  elP.textContent = bestMatch + ' is your BroNacho';

  localStorage.setItem('top3BroNachos',JSON.stringify(top3BroNachosObjArray));
  localStorage.setItem('bottom3BroNachos',JSON.stringify(bottom3BroNachosObjArray));
  localStorage.setItem('allUsers',JSON.stringify(allUsersObjectArrayOrdered));

  window.open('../html/results.html');

// console log all scores
  for( var i = 0; i < allUsersObjectArrayOrdered.length - 1; i++){
    console.log(allUsersObjectArrayOrdered[i].userName + ' ' + allUsersObjectArrayOrdered[i].matchesWithNewUser);
  }
}

function compareToEachUser() {

  var last = allUsersObjectArray.length - 1;
  var counter = 0;

  for(var i = 0; i < allUsersObjectArray.length - 1; i++) {
    for(var j = 0; j < allUsersObjectArray[i].userToppingsArray.length; j++) {
      if(allUsersObjectArray[i].userToppingsArray[j] === allUsersObjectArray[last].userToppingsArray[j] && (allUsersObjectArray[last].userToppingsArray[j] === true)) {
        counter = counter + 2;
      }
      if(allUsersObjectArray[i].userToppingsArray[j] === allUsersObjectArray[last].userToppingsArray[j] && (allUsersObjectArray[last].userToppingsArray[j] === false)) {
        counter = counter + 1;
      }
    }
    allUsersObjectArray[i].matchesWithNewUser = counter;
    counter = 0;
  }

  findBestMatch();
}

function findBestMatch() {

  allUsersObjectArrayOrdered = allUsersObjectArrayOrdered.concat(allUsersObjectArray);

  for(var f = 0; f < (allUsersObjectArrayOrdered.length - 2); f++) {
    var g = f + 1;
    if(allUsersObjectArrayOrdered[g].matchesWithNewUser > allUsersObjectArrayOrdered[f].matchesWithNewUser) {
      var toFront = allUsersObjectArrayOrdered[g];
      allUsersObjectArrayOrdered.splice(g,1);
      allUsersObjectArrayOrdered.unshift(toFront);
      f = -1;
    }
  }

  var last = allUsersObjectArrayOrdered.length - 2;

  bestMatch = allUsersObjectArrayOrdered[0].userName;
  bestMatchPic = allUsersObjectArrayOrdered[0].filePath;
  top3BroNachosObjArray = [allUsersObjectArrayOrdered[0],allUsersObjectArrayOrdered[1],allUsersObjectArrayOrdered[2]];
  bottom3BroNachosObjArray = [allUsersObjectArrayOrdered[last],allUsersObjectArrayOrdered[last - 1],allUsersObjectArrayOrdered[last - 2]];
  return bestMatch;
}
<|endoftext|>


<commit_before>/* Nitro Scheduled & Recurring Plugin
 * By Jono Cooper & George Czabania
 * Licensed under the BSD License
 */
plugin.add(function() {
	//Creates Scheduled List if it doesn't already exist
	if(!core.storage.lists.items.scheduled) {
		core.storage.lists.items.scheduled = {order: [], time: {name: 0, order: 0}};
	}

	//Creates a list item
	var obj = $$(ui.templates.listTemplate, {id: 'scheduled', name: $l._('scheduled')});
	$(document).ready(function() {
		//Adds to Sidebar
		$$.document.after(obj, $('#Lnext'));
		obj.view.$().attr('id', 'L' + obj.model.get('id'))

		//Updates Count
		obj.view.$('.count').html(core.list('scheduled').populate().length);
	});

	plugin.scheduled = {
		core: {
			add: function(name, type) {
				//ID of task
				var taskId = core.storage.tasks.length;
				core.storage.tasks.length++;

				if (type === 'scheduled') {
					core.storage.tasks[taskId] = {
						content: name,
						priority: 'none',
						date: '',
						notes: '',
						list: 'today',
						type: 'scheduled',
						next: '0',
						date: '',
						synced: false,
						time: {
							content: 0,
							priority: 0,
							date: 0,
							notes: 0,
							list: 0,
							type: 0,
							next: 0,
							date: 0
						}
					}

				} else if (type === 'recurring') {
					core.storage.tasks[taskId] = {
						content: name,
						priority: 'none',
						date: '',
						notes: '',
						list: 'today',
						type: 'recurring',
						next: '0',
						date: '',
						recurType: 'daily',
						recurInterval: [1],
						ends: '0',
						synced: false,
						time: {
							content: 0,
							priority: 0,
							date: 0,
							notes: 0,
							list: 0,
							type: 0,
							next: 0,
							date: 0,
							recurType: 0,
							recurInterval: 0,
							ends: 0
						}
					}
				}
				//Pushes to order
				core.storage.lists.items.scheduled.order.unshift(taskId);
				core.storage.save();
				console.log("Added a new " + type + " task")
			},

			update: function() {
				//Loops through all da tasks
				for (var i=0; i < core.storage.lists.items.scheduled.order.length; i++) {

					//Defines task for later
					var id = core.storage.lists.items.scheduled.order[i];
					var task = core.storage.tasks[id];

					if (task.next != '0') {

						//Add the task to the list if the date has been passed
						if (new Date(task.next).getTime() <= new Date().getTime()) {

							//Makes a new Task
							core.task().add(task.content, task.list);
							var data = core.storage.tasks[core.storage.tasks.length -1];

							//Sets Data
							data.notes = task.notes;
							data.priority = task.priority;

							//Task is scheduled
							if (task.type == 'scheduled') {

								//Deletes from scheduled		\
								console.log(id)
								core.task(id).move('trash');
								console.log('Task: ' + id + ' has been scheduled');

							//Task is recurring
							} else if (task.type == 'recurring') {

								//Checks Ends
								if (task.ends != 0 || task.ends != '') {
									//If it's ended
									if (new Date(task.ends).getTime() <= new Date().getTime()) {
										//Task has finished.
										console.log('The recurring has come to an end. Casting into oblivion.');
										core.task(id).move('trash');
										return;
									}
								}

								//Calculates Due Date
								if (task.date != '') {
									//Adds number to next
									var tmpdate = new Date(task.next);
									tmpdate.setDate(tmpdate.getDate() + parseInt(task.date));
									data.date = tmpdate.getTime();
								}

								//Change the Next Date
								if (task.recurType == 'daily') {
									var tmpdate = new Date(task.next);
									tmpdate.setDate(tmpdate.getDate() + task.recurInterval[0]);
									task.next = tmpdate.getTime();
								} else if (task.recurType == 'weekly') {
									var nextArr = [];

									//Loop through everything and create new dates
									for (var key in task.recurInterval) {
										//BROKEN. FIXME.
										/*
										//Checks if date has been passed
										if (new Date(task.recurInterval[key][2]).getTime() <= new Date().getTime()) {
											//If it has, we'll work out the next date.
											task.recurInterval[key][2] = cli.calc.dateConvert(Date.parse(task.recurInterval[key][2]).addWeeks(parseInt(task.recurInterval[key][0]) - 1).moveToDayOfWeek(parseInt(task.recurInterval[key][1])));
										}

										//Even if it hasn't, we'll still push it to an array.
										nextArr.push(new Date(task.recurInterval[key][2]).getTime());
										*/
									}
									//Next date as the next one coming up
									task.next = Array.min(nextArr).getTime();
								} else if (task.recurType == 'monthly') {
									var nextArr = []

									//Loop through everything and create new dates
									for (var key in task.recurInterval) {
										//Checks if date has been passed
										if (new Date(task.recurInterval[key][3]).getTime() <= new Date().getTime()) {
											if (task.recurInterval[key][2] == 'day') {

												//BROKEN. FIXME
												/*
												if (Date.today().set({day: task.recurInterval[key][1]}).getTime() <= new Date().getTime()) {
													//If it's been, set it for the next month
													task.recurInterval[key][3] = cli.calc.dateConvert(Date.today().set({day: task.recurInterval[key][1]}).addMonths(1).getTime());
												} else {
													//If it hasn't, set it for this month
													task.recurInterval[key][3] = cli.calc.dateConvert(Date.today().set({day: task.recurInterval[key][1]}).getTime());
												}*/
											} else {
												var namearr = ['zero', 'set({day: 1})', 'second()', 'third()', 'fourth()', 'last()'];
												var datearr = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
												//Fuckit. Using eval. Stupid date.js
												//BROKEN. FIXME
												/*var result = eval('Date.today().' + namearr[task.recurInterval[key][1]] + '.' + datearr[task.recurInterval[key][2]] + '()')

												console.log(result)

												//If it's already been, next month
												if (result.getTime() < new Date().getTime()) {
													var result = eval('Date.today().' + namearr[task.recurInterval[key][1]] + '.addMonths(1).' + datearr[task.recurInterval[key][2]] + '()')
												}

												task.recurInterval[key][3] = cli.calc.dateConvert(new Date(result));*/
											}
										}

										//Even if it hasn't, we'll still push it to an array.
										nextArr.push(new Date(task.recurInterval[key][3]).getTime());
									}

									//Next date as the next one coming up
									task.next = Array.min(nextArr).getTime();

								}
								console.log('Task: ' + i + ' has been recurred')
							}
							core.storage.save();
						};
					};
				};
			}
		},

		ui: {
			add: function() {
				alert('adding')
			}
		}
	}
});

//Because I'm lazy.
Array.max = function( array ){
    return Math.max.apply( Math, array );
};
Array.min = function( array ){
    return Math.min.apply( Math, array );
};<commit_msg>Recurring tasks work (I hope)<commit_after>/* Nitro Scheduled & Recurring Plugin
 * By Jono Cooper & George Czabania
 * Licensed under the BSD License
 */
plugin.add(function() {
	//Creates Scheduled List if it doesn't already exist
	if(!core.storage.lists.items.scheduled) {
		core.storage.lists.items.scheduled = {order: [], time: {name: 0, order: 0}};
	}

	//Creates a list item
	var obj = $$(ui.templates.listTemplate, {id: 'scheduled', name: $l._('scheduled')});
	$(document).ready(function() {
		//Adds to Sidebar
		$$.document.after(obj, $('#Lnext'));
		obj.view.$().attr('id', 'L' + obj.model.get('id'))

		//Updates Count
		obj.view.$('.count').html(core.list('scheduled').populate().length);
	});

	plugin.scheduled = {
		core: {
			add: function(name, type) {
				//ID of task
				var taskId = core.storage.tasks.length;
				core.storage.tasks.length++;

				if (type === 'scheduled') {
					core.storage.tasks[taskId] = {
						content: name,
						priority: 'none',
						date: '',
						notes: '',
						list: 'today',
						type: 'scheduled',
						next: '0',
						date: '',
						synced: false,
						time: {
							content: 0,
							priority: 0,
							date: 0,
							notes: 0,
							list: 0,
							type: 0,
							next: 0,
							date: 0
						}
					}

				} else if (type === 'recurring') {
					core.storage.tasks[taskId] = {
						content: name,
						priority: 'none',
						date: '',
						notes: '',
						list: 'today',
						type: 'recurring',
						next: '0',
						date: '',
						recurType: 'daily',
						recurInterval: [1],
						ends: '0',
						synced: false,
						time: {
							content: 0,
							priority: 0,
							date: 0,
							notes: 0,
							list: 0,
							type: 0,
							next: 0,
							date: 0,
							recurType: 0,
							recurInterval: 0,
							ends: 0
						}
					}
				}
				//Pushes to order
				core.storage.lists.items.scheduled.order.unshift(taskId);
				core.storage.save();
				console.log("Added a new " + type + " task")
			},

			update: function() {
				//Loops through all da tasks
				for (var i=0; i < core.storage.lists.items.scheduled.order.length; i++) {

					//Defines task for later
					var id = core.storage.lists.items.scheduled.order[i];
					var task = core.storage.tasks[id];

					if (task.next != '0') {

						//Add the task to the list if the date has been passed
						if (new Date(task.next).getTime() <= new Date().getTime()) {

							//Makes a new Task
							core.task().add(task.content, task.list);
							var data = core.storage.tasks[core.storage.tasks.length -1];

							//Sets Data
							data.notes = task.notes;
							data.priority = task.priority;

							//Task is scheduled
							if (task.type == 'scheduled') {

								//Deletes from scheduled
								console.log(id)
								core.task(id).move('trash');
								console.log('Task: ' + id + ' has been scheduled');

							//Task is recurring
							} else if (task.type == 'recurring') {

								//Checks Ends
								if (task.ends != 0 || task.ends != '') {
									//If it's ended
									if (new Date(task.ends).getTime() <= new Date().getTime()) {
										//Task has finished.
										console.log('The recurring has come to an end. Casting into oblivion.');
										core.task(id).move('trash');
										return;
									}
								}

								//Calculates Due Date
								if (task.date != '') {
									//Adds number to next
									var tmpdate = new Date(task.next);
									tmpdate.setDate(tmpdate.getDate() + parseInt(task.date));
									data.date = tmpdate.getTime();
								}

								//Change the Next Date
								if (task.recurType == 'daily') {
									var tmpdate = new Date(task.next);
									tmpdate.setDate(tmpdate.getDate() + task.recurInterval[0]);
									task.next = tmpdate.getTime();
								} else if (task.recurType == 'weekly') {
									var nextArr = [];

									//Loop through everything and create new dates
									for (var key in task.recurInterval) {
										//Checks if date has been passed
										if (new Date(task.recurInterval[key][2]).getTime() <= new Date().getTime()) {
											//If it has, we'll work out the next date.

											//Adds Weeks
											task.recurInterval[key][2] = new Date(task.recurInterval[key][2]).setDate(new Date(task.recurInterval[key][2]).getDate() + (7 * parseInt(task.recurInterval[key][0])))

											//Adds Days
											var next = parseInt(task.recurInterval[key][1]),
											day = new Date(task.recurInterval[key][2]).getDay(),
											diff = (next - day) == 0 ? 7 : (next - day);

											//Final Date
											task.recurInterval[key][2] = new Date(task.recurInterval[key][2]).setDate(task.recurInterval[key][2] .getDate() + diff);

											//task.recurInterval[key][2] = cli.calc.dateConvert(Date.parse(task.recurInterval[key][2]).addWeeks(parseInt(task.recurInterval[key][0]) - 1).moveToDayOfWeek(parseInt(task.recurInterval[key][1])));
										}

										//Even if it hasn't, we'll still push it to an array.
										nextArr.push(new Date(task.recurInterval[key][2]).getTime());
									}
									//Next date as the next one coming up
									task.next = Array.min(nextArr).getTime();
								} else if (task.recurType == 'monthly') {
									var nextArr = []

									//Loop through everything and create new dates
									for (var key in task.recurInterval) {
										//Checks if date has been passed
										if (new Date(task.recurInterval[key][3]).getTime() <= new Date().getTime()) {
											if (task.recurInterval[key][2] == 'day') {

												//BROKEN. FIXME
												if (new Date.setDate(task.recurInterval[key][1]).getTime() <= new Date().getTime()) {
													//If it's been, set it for the next month
													task.recurInterval[key][3] = new Date().setDate(task.recurInterval[key][1]).setMonth(new Date().getMonth() + 1).getTime();
												} else {
													//If it hasn't, set it for this month
													task.recurInterval[key][3] = new Date().setDate(task.recurInterval[key][1]).getTime();
												}
											} else {
												//BROKEN. FIXME
												//This is a piece of crap that I don't plan to implement unless someone tells me to.
												/*
												var namearr = ['zero', 'set({day: 1})', 'second()', 'third()', 'fourth()', 'last()'];
												var datearr = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
												//Fuckit. Using eval. Stupid date.j
												/*var result = eval('Date.today().' + namearr[task.recurInterval[key][1]] + '.' + datearr[task.recurInterval[key][2]] + '()')

												console.log(result)

												//If it's already been, next month
												if (result.getTime() < new Date().getTime()) {
													var result = eval('Date.today().' + namearr[task.recurInterval[key][1]] + '.addMonths(1).' + datearr[task.recurInterval[key][2]] + '()')
												}

												task.recurInterval[key][3] = cli.calc.dateConvert(new Date(result));*/
											}
										}

										//Even if it hasn't, we'll still push it to an array.
										nextArr.push(new Date(task.recurInterval[key][3]).getTime());
									}

									//Next date as the next one coming up
									task.next = Array.min(nextArr).getTime();

								}
								console.log('Task: ' + i + ' has been recurred')
							}
							core.storage.save();
						};
					};
				};
			}
		},

		ui: {
			add: function() {
				alert('adding')
			}
		}
	}
});

//Because I'm lazy.
Array.max = function( array ){
    return Math.max.apply( Math, array );
};
Array.min = function( array ){
    return Math.min.apply( Math, array );
};<|endoftext|>


<commit_before>/*
 * Table.js
 *
 * Copyright (c) 2011, OSBI Ltd. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 */
/**
 * Class which handles table rendering of resultsets
 */
var Table = Backbone.View.extend({
    tagName: "table",

    events: {
        'click .cancel': 'cancel',
        'click th.row' : 'clicked_cell',
        'click th.col' : 'clicked_cell'
    },

    initialize: function(args) {
        this.workspace = args.workspace;

        // Bind table rendering to query result event
        _.bindAll(this, "render", "process_data", "cancelled", "cancel");
        this.workspace.bind('query:result', this.render);
    },

    clicked_cell: function(event) {
        var self = this;

        if (this.workspace.query.get('type') != 'QM' || Settings.MODE == "view") {
            return false;
        }

        $target = ($(event.target).hasClass('row') || $(event.target).hasClass('col') ) ?
            $(event.target).find('div') : $(event.target);

    $body = $(document);
    $body.off('.contextMenu .contextMenuAutoHide');
    $('.context-menu-list').remove();
    $.contextMenu('destroy');
    $.contextMenu({
        appendTo: $target,
        selector: '.row, .col',
        ignoreRightClick: true,
         build: function($trigger, e) {
            $target = $(e.currentTarget).find('div');
            var axis = $(e.currentTarget).hasClass('rows') ? "ROWS" : "COLUMNS"
            var pos = $target.attr('rel').split(':');
            var row = parseInt(pos[0])
            var col = parseInt(pos[1])
            var cell = self.workspace.query.result.lastresult().cellset[row][col];
            var query = self.workspace.query;
            var schema = query.get('schema');
            var cube = query.get('connection') + "/" +
                query.get('catalog') + "/"
                + ((schema == "" || schema == null) ? "null" : schema)
                + "/" + query.get('cube');

            var d = cell.properties.dimension;
            var h = cell.properties.hierarchy;
            var l = cell.properties.level;

            var keep_payload = JSON.stringify(
                {
                    "hierarchy"     : "[" + h + "]",
                    "uniquename"    : l,
                    "type"          : "level",
                    "action"        : "delete"
                })
            + "," +JSON.stringify(
                {
                    "hierarchy"     : "[" + h + "]",
                    "uniquename"    : cell.properties.uniquename,
                    "type"          : "member",
                    "action"        : "add"
                }
            );

            var levels = [];
            var items = {};
            var dimensions = Saiku.session.sessionworkspace.dimensions[cube].get('data');
            var dimsel = {};
            var used_levels = [];

            self.workspace.query.action.get("/axis/" + axis + "/dimension/" + d, {
                        success: function(response, model) {
                            dimsel = model;
                        },
                        async: false
            });

            _.each(dimsel.selections, function(selection) {
                if(_.indexOf(used_levels, selection.levelUniqueName) == -1)
                    used_levels.push(selection.levelUniqueName);

            });

            _.each(dimensions, function(dimension) {
                if (dimension.name == d) {
                    _.each(dimension.hierarchies, function(hierarchy) {
                        if (hierarchy.name == h) {
                            _.each(hierarchy.levels, function(level) {
                                items[level.name] = {
                                    name: level.name,
                                    payload: JSON.stringify({
                                        "hierarchy"     : "[" + h + "]",
                                        uniquename    : level.uniqueName,
                                        type          : "level",
                                        action        : "add"
                                    })
                                };
                                if(_.indexOf(used_levels, level.uniqueName) > -1) {
                                    items[level.name].disabled = true;
                                    items["remove-" + level.name] = {
                                        name: level.name,
                                        payload: JSON.stringify({
                                            "hierarchy"     : "[" + h + "]",
                                            uniquename    : level.uniqueName,
                                            type          : "level",
                                            action        : "delete"
                                        })
                                    };

                                }
                                items["keep-" + level.name] = items[level.name];
                                items["include-" + level.name] = JSON.parse(JSON.stringify(items[level.name]));
                                items["keep-" + level.name].payload = keep_payload + "," + items[level.name].payload;
                            });
                        }
                    });
                }
            });
            items["keeponly"] = { payload: keep_payload }

            var lvlitems = function(prefix) {
                var ritems = {};
                for (key in items) {
                    if (prefix != null && prefix.length < key.length && key.substr(0, prefix.length) == prefix) {
                            ritems[key] = items[key];
                    }
                }
                return ritems;
            }

            var member = $target.html();

            var citems = {
                    "name" : {name: "" + member + "", disabled: true },
                    "sep1": "---------",
                    "keeponly": {name: "Keep Only", payload: keep_payload },
            };
            if (d != "Measures") {
                citems["fold1key"] = {
                        name: "Include Level",
                        items: lvlitems("include-")
                    };
                citems["fold2key"] = {
                        name: "Keep and Include Level",
                        items: lvlitems("keep-")
                    };
                citems["fold3key"] = {
                        name: "Remove Level",
                        items: lvlitems("remove-")
                    };
            }
            return {
                callback: function(key, options) {
                    self.workspace.query.action.put('/axis/' + axis + '/dimension/' + d, {
                        success: function() {
                            self.workspace.query.clear();
                            self.workspace.query.fetch({ success: function() {

                                $(self.workspace.el).find('.fields_list_body ul').empty();
                                $(self.workspace.dimension_list.el).find('.parent_dimension a.folder_collapsed').removeAttr('style');

                                $(self.workspace.dimension_list.el).find('.parent_dimension ul li')
                                    .draggable('enable')
                                    .css({ fontWeight: 'normal' });

                                $(self.workspace.measure_list.el).find('a.measure').parent()
                                    .draggable('enable')
                                    .css({ fontWeight: 'normal' });

                                self.workspace.populate_selections(self.workspace.measure_list.el);
                                $(self.workspace.el).find('.fields_list_body ul li')
                                    .removeClass('ui-draggable-disabled ui-state-disabled')
                                    .css({ fontWeight: 'normal' });

                             }});

                        },
                        data: {
                            selections: "[" + items[key].payload + "]"
                        }
                    });

                },
                items: citems
            }
        }
    });
    $target.contextMenu();

    },

    render: function(args, block) {
        if (args.data.error != null) {
            return this.error(args);
        }

        // Check to see if there is data
        if (args.data.cellset && args.data.cellset.length === 0) {
            return this.no_results(args);
        }

        // Clear the contents of the table
        $(this.el).html('
Rendering ' + args.data.width + ' columns and ' + args.data.height + ' rows...
');

        // Render the table without blocking the UI thread
        if (block === true) {
            this.process_data(args.data.cellset);
        } else {
            _.delay(this.process_data, 0, args.data.cellset);
        }

    },

    process_data: function(data) {
        var contents = "";
        var table = data ? data : [];
        var colSpan;
        var colValue;
        var isHeaderLowestLvl;

        for (var row = 0; row < table.length; row++) {
            contents += "
";
            colSpan = 0;
            colValue = "";
            isHeaderLowestLvl = false;
            for (var col = 0; col < table[row].length; col++) {
                var header = data[row][col];

                // FIXME - this needs to be cleaned up

                // If the cell is a column header and is null (top left of table)
                if (header.type === "COLUMN_HEADER" && header.value === "null") {
                    contents += '

	';
                } // If the cell is a column header and isn't null (column header of table)
                else if (header.type === "COLUMN_HEADER") {
                    if ((colValue == "") && (table[row].length == 1) || isHeaderLowestLvl) {
                        contents += '
' + header.value + '
	';
                    } else if ((colValue == "") && (table[row].length > col+1)) {
                        colValue = header.value;
                        colSpan++;
                    } else {
                        if (colValue != header.value) {
                            contents += '
' + colValue + '
	';
                            colValue = header.value;
                            colSpan = 1;
                        } else {
                            colSpan++;
                        }

                        if (table[row].length == col+1)
                            contents += '
' + colValue + '
	';
                    }
                } // If the cell is a row header and is null (grouped row header)
                else if (header.type === "ROW_HEADER" && header.value === "null") {
                    contents += '

	';
                } // If the cell is a row header and isn't null (last row header)
                else if (header.type === "ROW_HEADER") {
                    contents += '
' + header.value + '
	';
                }
                else if (header.type === "ROW_HEADER_HEADER") {
                    contents += '
' + header.value + '
	';
                    isHeaderLowestLvl = true;
                } // If the cell is a normal data cell
                else if (header.type === "DATA_CELL") {
                    contents += '
' + header.value + '
	';
                }
            }
            contents += "
";
        }

        // Append the table
        $(this.el).html(contents);
        this.post_process();
    },    post_process: function() {
        if (this.workspace.query.get('type') == 'QM' && Settings.MODE != "view") {
            $(this.el).find('th.row, th.col').addClass('headerhighlight');
        }
    },
    cancel: function(event) {
        this.workspace.query.action.del("/result", {success: this.cancelled } );
    },

    cancelled: function(args) {
        $(this.el).html('
No results
');
    },

    no_results: function(args) {
        $(this.el).html('
No results
');
    },

    error: function(args) {
        $(this.el).html('
' + args.data.error + '
');
    }
});
<commit_msg>Better management of columns header in case of repeated values<commit_after>/*
 * Table.js
 *
 * Copyright (c) 2011, OSBI Ltd. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 */
/**
 * Class which handles table rendering of resultsets
 */
var Table = Backbone.View.extend({
    tagName: "table",

    events: {
        'click .cancel': 'cancel',
        'click th.row' : 'clicked_cell',
        'click th.col' : 'clicked_cell'
    },

    initialize: function(args) {
        this.workspace = args.workspace;

        // Bind table rendering to query result event
        _.bindAll(this, "render", "process_data", "cancelled", "cancel");
        this.workspace.bind('query:result', this.render);
    },

    clicked_cell: function(event) {
        var self = this;

        if (this.workspace.query.get('type') != 'QM' || Settings.MODE == "view") {
            return false;
        }

        $target = ($(event.target).hasClass('row') || $(event.target).hasClass('col') ) ?
            $(event.target).find('div') : $(event.target);

    $body = $(document);
    $body.off('.contextMenu .contextMenuAutoHide');
    $('.context-menu-list').remove();
    $.contextMenu('destroy');
    $.contextMenu({
        appendTo: $target,
        selector: '.row, .col',
        ignoreRightClick: true,
         build: function($trigger, e) {
            $target = $(e.currentTarget).find('div');
            var axis = $(e.currentTarget).hasClass('rows') ? "ROWS" : "COLUMNS"
            var pos = $target.attr('rel').split(':');
            var row = parseInt(pos[0])
            var col = parseInt(pos[1])
            var cell = self.workspace.query.result.lastresult().cellset[row][col];
            var query = self.workspace.query;
            var schema = query.get('schema');
            var cube = query.get('connection') + "/" +
                query.get('catalog') + "/"
                + ((schema == "" || schema == null) ? "null" : schema)
                + "/" + query.get('cube');

            var d = cell.properties.dimension;
            var h = cell.properties.hierarchy;
            var l = cell.properties.level;

            var keep_payload = JSON.stringify(
                {
                    "hierarchy"     : "[" + h + "]",
                    "uniquename"    : l,
                    "type"          : "level",
                    "action"        : "delete"
                })
            + "," +JSON.stringify(
                {
                    "hierarchy"     : "[" + h + "]",
                    "uniquename"    : cell.properties.uniquename,
                    "type"          : "member",
                    "action"        : "add"
                }
            );

            var levels = [];
            var items = {};
            var dimensions = Saiku.session.sessionworkspace.dimensions[cube].get('data');
            var dimsel = {};
            var used_levels = [];

            self.workspace.query.action.get("/axis/" + axis + "/dimension/" + d, {
                        success: function(response, model) {
                            dimsel = model;
                        },
                        async: false
            });

            _.each(dimsel.selections, function(selection) {
                if(_.indexOf(used_levels, selection.levelUniqueName) == -1)
                    used_levels.push(selection.levelUniqueName);

            });

            _.each(dimensions, function(dimension) {
                if (dimension.name == d) {
                    _.each(dimension.hierarchies, function(hierarchy) {
                        if (hierarchy.name == h) {
                            _.each(hierarchy.levels, function(level) {
                                items[level.name] = {
                                    name: level.name,
                                    payload: JSON.stringify({
                                        "hierarchy"     : "[" + h + "]",
                                        uniquename    : level.uniqueName,
                                        type          : "level",
                                        action        : "add"
                                    })
                                };
                                if(_.indexOf(used_levels, level.uniqueName) > -1) {
                                    items[level.name].disabled = true;
                                    items["remove-" + level.name] = {
                                        name: level.name,
                                        payload: JSON.stringify({
                                            "hierarchy"     : "[" + h + "]",
                                            uniquename    : level.uniqueName,
                                            type          : "level",
                                            action        : "delete"
                                        })
                                    };

                                }
                                items["keep-" + level.name] = items[level.name];
                                items["include-" + level.name] = JSON.parse(JSON.stringify(items[level.name]));
                                items["keep-" + level.name].payload = keep_payload + "," + items[level.name].payload;
                            });
                        }
                    });
                }
            });
            items["keeponly"] = { payload: keep_payload }

            var lvlitems = function(prefix) {
                var ritems = {};
                for (key in items) {
                    if (prefix != null && prefix.length < key.length && key.substr(0, prefix.length) == prefix) {
                            ritems[key] = items[key];
                    }
                }
                return ritems;
            }

            var member = $target.html();

            var citems = {
                    "name" : {name: "" + member + "", disabled: true },
                    "sep1": "---------",
                    "keeponly": {name: "Keep Only", payload: keep_payload },
            };
            if (d != "Measures") {
                citems["fold1key"] = {
                        name: "Include Level",
                        items: lvlitems("include-")
                    };
                citems["fold2key"] = {
                        name: "Keep and Include Level",
                        items: lvlitems("keep-")
                    };
                citems["fold3key"] = {
                        name: "Remove Level",
                        items: lvlitems("remove-")
                    };
            }
            return {
                callback: function(key, options) {
                    self.workspace.query.action.put('/axis/' + axis + '/dimension/' + d, {
                        success: function() {
                            self.workspace.query.clear();
                            self.workspace.query.fetch({ success: function() {

                                $(self.workspace.el).find('.fields_list_body ul').empty();
                                $(self.workspace.dimension_list.el).find('.parent_dimension a.folder_collapsed').removeAttr('style');

                                $(self.workspace.dimension_list.el).find('.parent_dimension ul li')
                                    .draggable('enable')
                                    .css({ fontWeight: 'normal' });

                                $(self.workspace.measure_list.el).find('a.measure').parent()
                                    .draggable('enable')
                                    .css({ fontWeight: 'normal' });

                                self.workspace.populate_selections(self.workspace.measure_list.el);
                                $(self.workspace.el).find('.fields_list_body ul li')
                                    .removeClass('ui-draggable-disabled ui-state-disabled')
                                    .css({ fontWeight: 'normal' });

                             }});

                        },
                        data: {
                            selections: "[" + items[key].payload + "]"
                        }
                    });

                },
                items: citems
            }
        }
    });
    $target.contextMenu();

    },

    render: function(args, block) {
        if (args.data.error != null) {
            return this.error(args);
        }

        // Check to see if there is data
        if (args.data.cellset && args.data.cellset.length === 0) {
            return this.no_results(args);
        }

        // Clear the contents of the table
        $(this.el).html('
Rendering ' + args.data.width + ' columns and ' + args.data.height + ' rows...
');

        // Render the table without blocking the UI thread
        if (block === true) {
            this.process_data(args.data.cellset);
        } else {
            _.delay(this.process_data, 0, args.data.cellset);
        }

    },

    process_data: function(data) {
        var contents = "";
        var table = data ? data : [];
        var colSpan;
        var colValue;
        var isHeaderLowestLvl;
        var isLastColumn;
        var nextHeader;

        for (var row = 0; row < table.length; row++) {
            contents += "
";
            colSpan = 1;
            colValue = "";
            isHeaderLowestLvl = false;
            isLastColumn = false;
            for (var col = 0; col < table[row].length; col++) {
                var header = data[row][col];

                // FIXME - this needs to be cleaned up

                // If the cell is a column header and is null (top left of table)
                if (header.type === "COLUMN_HEADER" && header.value === "null") {
                    contents += '

	';
                } // If the cell is a column header and isn't null (column header of table)
                else if (header.type === "COLUMN_HEADER") {
                    if (table[row].length == col+1)
                        isLastColumn = true;
                    else
                        nextHeader = data[row][col+1];

                    if (isHeaderLowestLvl) {
                        // Is a lowest level in the column header. It is always 1 cell wide
                        contents += '
' + header.value + '
	';
                    } else if (isLastColumn) {
                        // Last column in a row....
                        contents += '
' + header.value + '
	';
                    } else {
                        // All the rest...
                        if (header.value != nextHeader.value) {
                            contents += '
' + header.value + '
	';
                            colSpan = 1;
                        } else {
                            colSpan++;
                        }
                    }
                } // If the cell is a row header and is null (grouped row header)
                else if (header.type === "ROW_HEADER" && header.value === "null") {
                    contents += '

	';
                } // If the cell is a row header and isn't null (last row header)
                else if (header.type === "ROW_HEADER") {
                    contents += '
' + header.value + '
	';
                }
                else if (header.type === "ROW_HEADER_HEADER") {
                    contents += '
' + header.value + '
	';
                    isHeaderLowestLvl = true;
                } // If the cell is a normal data cell
                else if (header.type === "DATA_CELL") {
                    contents += '
' + header.value + '
	';
                }
            }
            contents += "
";
        }

        // Append the table
        $(this.el).html(contents);
        this.post_process();
    },    post_process: function() {
        if (this.workspace.query.get('type') == 'QM' && Settings.MODE != "view") {
            $(this.el).find('th.row, th.col').addClass('headerhighlight');
        }
    },
    cancel: function(event) {
        this.workspace.query.action.del("/result", {success: this.cancelled } );
    },

    cancelled: function(args) {
        $(this.el).html('
No results
');
    },

    no_results: function(args) {
        $(this.el).html('
No results
');
    },

    error: function(args) {
        $(this.el).html('
' + args.data.error + '
');
    }
});
<|endoftext|>