<commit_before>$(function () {
  document.title = String(document.title) + " (testing)"
});

var TestingSupervisor = {
  chooseSingle: function (arg, predicate) {
    if (!_.isArray(arg)) {
      var key = this.chooseSingle(_.keys(arg), predicate);
      return arg[key];
    }
    var passing = _.select(arg, function (id) {
      return predicate(id);
    });
    if (passing.length != 1)
      throw new Error("Invalid number of predicate-passing of items: " + passing.length);
    return passing[0];
  },
  chooseVisible: function (arg) {
    return this.chooseSingle(arg, function (id) {
      return $($i(id)).css('display') != 'none';
    });
  },
  chooseSelected: function (arg) {
    return this.chooseSingle(arg, function (id) {
      return $($i(id)).hasClass('selected');
    });
  },
  activeSection: function () {
    return this.chooseVisible(['overview', 'alerts', 'settings']);
  },
  activeGraphZoom: function () {
    return this.chooseSelected({
      'overview_graph_zoom_real_time': 'real_time',
      'overview_graph_zoom_one_hr' : 'one_hr',
      'overview_graph_zoom_day': 'day'
    });
  },
  activeKeysZoom: function () {
    return this.chooseSelected({
      'overview_keys_zoom_real_time': 'real_time',
      'overview_keys_zoom_one_hr' : 'one_hr',
      'overview_keys_zoom_day': 'day'
    });
  },
  activeStatsTarget: function () {
    var cell = DAO.cells.currentStatTargetCell;
    if (!cell)
      return null;
    var value = cell.value;
    if (!cell)
      return null;
    return [value.name, value.stats.uri];
  },
  installInterceptor: function (wrapperName, obj, methodName) {
    var self = this;
    var method = obj[methodName];
    var rv = obj[methodName] = function () {
      var args = [method].concat(_.toArray(arguments));
      return self[wrapperName].apply(self, args);
    }
    rv.originalMethod = method;
    return rv;
  },
  interceptAjax: function () {
    this.installInterceptor('interceptedAjax', $, 'ajax');
  },
  alertsResponse: {limit: 15,
                   settings: {updateURI: "/alerts/settings"},
                   list: [{number: 3,
                           type: "info",
                           tstamp: 1259836260000,
                           shortText: "Above Average Operations per Second",
                           text: "Licensing, capacity, NorthScale issues, etc."},
                          {number: 2,
                           type: "attention",
                           tstamp: 1259836260000,
                           shortText: "New Node Joined Pool",
                           text: "A new node is now online"},
                          {number: 1,
                           type: "warning",
                           tstamp: 1259836260000,
                           shortText: "Server Node Down",
                           text: "Server node is no longer available"}]},
  interceptedAjax: function (original, options) {
    if (options.type != 'GET')
      return; // original(options);
    console.log("intercepted ajax:", options);
    var url = options.url;
    var hostPrefix = document.location.protocol + ":/" + document.location.host;
    if (url.indexOf(hostPrefix) == 0)
      url = url.substring(hostPrefix);
    if (url.indexOf("/") == 0)
      url = url.substring(1);
    if (url.lastIndexOf("/") == url.length - 1)
      url = url.substring(0, url.length - 1);

    var path = url.split("/")

    var fakeResponse = function (data) {
      _.defer(function () {
        if (data instanceof Function) {
          data.call(null, fakeResponse);
          return;
        }
        options.success.call(null, data);
      });
    }

    var resp;
    if (path[0] == "pools") {
      if (path.length == 1) {
        // /pools
        resp = {pools: [
          {name: 'default',
           uri: "/pools/default"},
          {name: 'Another Pool',
           uri: '/pools/Another Pool'}]};
      } else {
        // /pools/:id
        if (path[1] == 'default') {
          resp = {nodes: [{ipAddress: "10.0.1.20",
                           status: "healthy",
                           ports: {routing: 11211,
                                   caching: 11311,
                                   kvstore: 11411},
                           name: "first_node",
                           fqdn: "first_node.in.pool.com"},
                          {ipAddress: "10.0.1.21",
                           status: "healthy",
                           ports: {routing: 11211,
                                   caching: 11311,
                                   kvstore: 11411},
                           uri: "/addresses/10.0.1.20",
                           name: "second_node",
                           fqdn: "second_node.in.pool.com"}],
                  buckets: [{uri: "/buckets/4",
                             name: "Excerciser Application"}],
                  stats: {uri: "/buckets/4/stats?really_for_pool=1"},
                  name: "Default Pool"};
        } else {
          resp = {nodes: [{ipAddress: "10.0.1.20",
                           status: "healthy",
                           ports: {routing: 11211,
                                   caching: 11311,
                                   kvstore: 11411},
                           name: "first_node",
                           fqdn: "first_node.in.pool.com"},
                          {ipAddress: "10.0.1.21",
                           status: "healthy",
                           ports: {routing: 11211,
                                   caching: 11311,
                                   kvstore: 11411},
                           uri: "/addresses/10.0.1.20",
                           name: "second_node",
                           fqdn: "second_node.in.pool.com"}],
                  buckets: [{uri: "/buckets/5",
                             name: "Excerciser Another"}],
                  stats: {uri: "/buckets/4/stats?really_for_pool=1"},
                  name: "Another Pool"};
        }
      }
    } else if (path[0] == 'buckets') {
      if (path.length == 2) {
        // /buckets/:id
        if (path[1] == "4")
          resp = {pool_uri: "asdasd",
                  stats: {uri: "/buckets/4/stats"},
                  name: "Excerciser Application"};
        else
          resp = {pool_uri: "asdasd",
                  stats: {uri: "/buckets/5/stats"},
                  name: "Excerciser Another"};
      } else {
        // /buckets/:id/stats
        var params = options["data"];
        var opsPerSecondZoom = params['opsPerSecondZoom'] || "now";
        var allSamples = {
          '1hr': {"gets":[3,14,23,52,45,25,23,22,50,67,59,55,54,41,36,35,26,61,72,49,60],
                  "misses":[23,14,45,64,41,45,43,25,14,11,18,36,64,76,86,86,79,78,55,59,49],
                  "sets":[42,65,42,63,81,87,74,84,56,44,71,64,49,48,55,46,37,46,64,33,18],
                  "ops":[61,65,64,75,77,57,68,76,64,61,66,63,68,37,32,60,72,54,43,41,55]},
          'now': {"gets":[70,44,28,17,29,61,70,47,39,47,27,54,47,30,43,45,65,49,46,41,62],
                  "misses":[67,48,45,29,18,53,57,59,78,57,41,41,29,34,34,43,51,58,63,71,78],
                  "sets":[65,51,61,42,58,71,55,77,69,44,43,22,59,63,36,46,40,69,80,50,69],
                  "ops":[63,55,27,30,35,57,39,38,32,17,38,49,61,78,82,71,41,35,25,44,68]},
          '24hr': {"gets":[69,56,57,61,58,55,74,87,93,88,55,69,56,67,81,65,40,58,47,43,30],
                   "misses":[14,45,56,45,42,43,29,23,47,23,40,60,45,54,64,40,28,19,59,48,60],
                   "sets":[60,34,54,30,26,30,34,35,38,27,59,67,43,45,48,66,42,43,52,44,35],
                   "ops":[6,24,53,64,35,30,45,50,31,32,29,50,28,30,30,40,30,54,39,37,58]}};
        var samples = allSamples[opsPerSecondZoom];
        var samplesSize = samples["gets"].length;

        var samplesInterval = 5000;
        if (opsPerSecondZoom == "24hr")
          samplesInterval = 86400000 / samplesSize;
        else if (opsPerSecondZoom == "1hr")
          samplesInterval = 3600000 / samplesSize;

        var now = (new Date()).valueOf();
        var lastSampleTstamp = now;

        if (samplesInterval == 5000) {
          var rotates = ((now / 1000) >> 0) % samplesSize;
          var newSamples = {};
          for (var k in samples) {
            var data = samples[k];
            newSamples[k] = data.concat(data).slice(rotates, rotates + samplesSize);
          }
          samples = newSamples;
        }

        var startTstampParam = params["opsbysecondStartTStamp"];
        if (startTstampParam !== undefined) {
          var startTstamp = parseInt(startTstampParam, 10);

          var intervals = Math.floor((now - startTstampParam) / samplesInterval);
          if (intervals > samplesSize) {
            throw new Error("should not happen");
          }
          lastSampleTstamp = startTstamp + intervals * samplesInterval;

          var newSamples = {};
          for (var k in samples) {
            var data = samples[k];
            var newData = data.slice(-intervals);
            newSamples[k] = newData;
          }
          samples = newSamples;
        }

        var resp = {
          hot_keys: [{name: "user:image:value",
                      gets: 10000,
                      bucket: "Excerciser application",
                      misses: 100,
                      type: "Persistent"},
                     {name: "user:image:value2",
                      gets: 10000,
                      bucket: "Excerciser application",
                      misses: 100,
                      type: "Cache"},
                     {name: "user:image:value3",
                      gets: 10000,
                      bucket: "Excerciser application",
                      misses: 100,
                      type: "Persistent"},
                     {name: "user:image:value4",
                      gets: 10000,
                      bucket: "Excerciser application",
                      misses: 100,
                      type: "Cache"}],
          op: _.extend({tstamp: lastSampleTstamp,
                        'samplesInterval': samplesInterval},
                       samples)};
      }
    } else if (path[0] == 'alerts' && path.length == 1) {
      // /alerts
      resp = this.alertsResponse;
    } else {
      throw new Error("Unknown ajax path: " + options.url);
    }

    _.defer(function () {
      fakeResponse(resp);
    });
  }
};

TestingSupervisor.interceptAjax();
<commit_msg>a bit more correct data for mocked requests<commit_after>$(function () {
  document.title = String(document.title) + " (testing)"
});

var TestingSupervisor = {
  chooseSingle: function (arg, predicate) {
    if (!_.isArray(arg)) {
      var key = this.chooseSingle(_.keys(arg), predicate);
      return arg[key];
    }
    var passing = _.select(arg, function (id) {
      return predicate(id);
    });
    if (passing.length != 1)
      throw new Error("Invalid number of predicate-passing of items: " + passing.length);
    return passing[0];
  },
  chooseVisible: function (arg) {
    return this.chooseSingle(arg, function (id) {
      return $($i(id)).css('display') != 'none';
    });
  },
  chooseSelected: function (arg) {
    return this.chooseSingle(arg, function (id) {
      return $($i(id)).hasClass('selected');
    });
  },
  activeSection: function () {
    return this.chooseVisible(['overview', 'alerts', 'settings']);
  },
  activeGraphZoom: function () {
    return this.chooseSelected({
      'overview_graph_zoom_real_time': 'real_time',
      'overview_graph_zoom_one_hr' : 'one_hr',
      'overview_graph_zoom_day': 'day'
    });
  },
  activeKeysZoom: function () {
    return this.chooseSelected({
      'overview_keys_zoom_real_time': 'real_time',
      'overview_keys_zoom_one_hr' : 'one_hr',
      'overview_keys_zoom_day': 'day'
    });
  },
  activeStatsTarget: function () {
    var cell = DAO.cells.currentStatTargetCell;
    if (!cell)
      return null;
    var value = cell.value;
    if (!cell)
      return null;
    return [value.name, value.stats.uri];
  },
  installInterceptor: function (wrapperName, obj, methodName) {
    var self = this;
    var method = obj[methodName];
    var rv = obj[methodName] = function () {
      var args = [method].concat(_.toArray(arguments));
      return self[wrapperName].apply(self, args);
    }
    rv.originalMethod = method;
    return rv;
  },
  interceptAjax: function () {
    this.installInterceptor('interceptedAjax', $, 'ajax');
  },
  alertsResponse: {limit: 15,
                   settings: {updateURI: "/alerts/settings"},
                   list: [{number: 3,
                           type: "info",
                           tstamp: 1259836260000,
                           shortText: "Above Average Operations per Second",
                           text: "Licensing, capacity, NorthScale issues, etc."},
                          {number: 2,
                           type: "attention",
                           tstamp: 1259836260000,
                           shortText: "New Node Joined Pool",
                           text: "A new node is now online"},
                          {number: 1,
                           type: "warning",
                           tstamp: 1259836260000,
                           shortText: "Server Node Down",
                           text: "Server node is no longer available"}]},
  interceptedAjax: function (original, options) {
    if (options.type != 'GET')
      return; // original(options);
    console.log("intercepted ajax:", options);
    var url = options.url;
    var hostPrefix = document.location.protocol + ":/" + document.location.host;
    if (url.indexOf(hostPrefix) == 0)
      url = url.substring(hostPrefix);
    if (url.indexOf("/") == 0)
      url = url.substring(1);
    if (url.lastIndexOf("/") == url.length - 1)
      url = url.substring(0, url.length - 1);

    var path = url.split("/")

    var fakeResponse = function (data) {
      _.defer(function () {
        if (data instanceof Function) {
          data.call(null, fakeResponse);
          return;
        }
        options.success.call(null, data);
      });
    }

    var resp;
    if (path[0] == "pools") {
      if (path.length == 1) {
        // /pools
        resp = {pools: [
          {name: 'default',
           uri: "/pools/default"}]};
      } else {
        // /pools/:id
        resp = {nodes: [{hostname: "mickey-mouse.disney.com",
                         status: "healthy",
                         ports: {proxy: 11211,
                                 direct: 11311},
                         otp_node: "ns1@mickey-mouse.disney.com",
                         otp_cookie: "SADFDFGDFG"},
                        {hostname: "donald-duck.disney.com",
                         status: "healthy",
                         ports: {proxy: 11211,
                                 direct: 11311},
                         otp_node: "ns1@donald-duck.disney.com",
                         otp_cookie: "SADFDFGDFG"},
                        {hostname: "goofy.disney.com",
                         status: "healthy",
                         ports: {proxy: 11211,
                                 direct: 11311},
                         otp_node: "ns1@goofy.disney.com",
                         otp_cookie: "SADFDFGDFG"}],
                buckets: [{uri: "/buckets/4",
                           name: "default"},
                          {uri: "/buckets/5",
                           name: "Excerciser Application"},
                          {uri: "/buckets/6",
                           name: "new-year-site"},
                          {uri: "/buckets/7",
                           name: "new-year-site-staging"}],
                stats: {uri: "/buckets/4/stats?really_for_pool=1"},
                name: "Default Pool"};
      }
    } else if (path[0] == 'buckets') {
      if (path.length == 2) {
        // /buckets/:id
        if (path[1] == "5")
          resp = {nodes:[], // not used for now
                  testAppBucket: true,
                  controlURL: "asdasdasdasdasdasd",
                  status: false,
                  stats: {uri: "/buckets/5/stats"},
                  name: "Excerciser Application"};
        else
          resp = {nodes: [], // not used for now
                  stats: {uri: "/buckets/4/stats"},
                  name: "default"};
      } else {
        // /buckets/:id/stats
        var params = options["data"];
        var opsPerSecondZoom = params['opsPerSecondZoom'] || "now";
        var allSamples = {
          '1hr': {"gets":[3,14,23,52,45,25,23,22,50,67,59,55,54,41,36,35,26,61,72,49,60],
                  "misses":[23,14,45,64,41,45,43,25,14,11,18,36,64,76,86,86,79,78,55,59,49],
                  "sets":[42,65,42,63,81,87,74,84,56,44,71,64,49,48,55,46,37,46,64,33,18],
                  "ops":[61,65,64,75,77,57,68,76,64,61,66,63,68,37,32,60,72,54,43,41,55]},
          'now': {"gets":[70,44,28,17,29,61,70,47,39,47,27,54,47,30,43,45,65,49,46,41,62],
                  "misses":[67,48,45,29,18,53,57,59,78,57,41,41,29,34,34,43,51,58,63,71,78],
                  "sets":[65,51,61,42,58,71,55,77,69,44,43,22,59,63,36,46,40,69,80,50,69],
                  "ops":[63,55,27,30,35,57,39,38,32,17,38,49,61,78,82,71,41,35,25,44,68]},
          '24hr': {"gets":[69,56,57,61,58,55,74,87,93,88,55,69,56,67,81,65,40,58,47,43,30],
                   "misses":[14,45,56,45,42,43,29,23,47,23,40,60,45,54,64,40,28,19,59,48,60],
                   "sets":[60,34,54,30,26,30,34,35,38,27,59,67,43,45,48,66,42,43,52,44,35],
                   "ops":[6,24,53,64,35,30,45,50,31,32,29,50,28,30,30,40,30,54,39,37,58]}};
        var samples = allSamples[opsPerSecondZoom];
        var samplesSize = samples["gets"].length;

        var samplesInterval = 5000;
        if (opsPerSecondZoom == "24hr")
          samplesInterval = 86400000 / samplesSize;
        else if (opsPerSecondZoom == "1hr")
          samplesInterval = 3600000 / samplesSize;

        var now = (new Date()).valueOf();
        var lastSampleTstamp = now;

        if (samplesInterval == 5000) {
          var rotates = ((now / 1000) >> 0) % samplesSize;
          var newSamples = {};
          for (var k in samples) {
            var data = samples[k];
            newSamples[k] = data.concat(data).slice(rotates, rotates + samplesSize);
          }
          samples = newSamples;
        }

        var startTstampParam = params["opsbysecondStartTStamp"];
        if (startTstampParam !== undefined) {
          var startTstamp = parseInt(startTstampParam, 10);

          var intervals = Math.floor((now - startTstampParam) / samplesInterval);
          if (intervals > samplesSize) {
            throw new Error("should not happen");
          }
          lastSampleTstamp = startTstamp + intervals * samplesInterval;

          var newSamples = {};
          for (var k in samples) {
            var data = samples[k];
            var newData = data.slice(-intervals);
            newSamples[k] = newData;
          }
          samples = newSamples;
        }

        var resp = {
          hot_keys: [{name: "user:image:value",
                      gets: 10000,
                      bucket: "Excerciser application",
                      misses: 100,
                      type: "Persistent"},
                     {name: "user:image:value2",
                      gets: 10000,
                      bucket: "Excerciser application",
                      misses: 100,
                      type: "Cache"},
                     {name: "user:image:value3",
                      gets: 10000,
                      bucket: "Excerciser application",
                      misses: 100,
                      type: "Persistent"},
                     {name: "user:image:value4",
                      gets: 10000,
                      bucket: "Excerciser application",
                      misses: 100,
                      type: "Cache"}],
          op: _.extend({tstamp: lastSampleTstamp,
                        'samplesInterval': samplesInterval},
                       samples)};
      }
    } else if (path[0] == 'alerts' && path.length == 1) {
      // /alerts
      resp = this.alertsResponse;
    } else {
      throw new Error("Unknown ajax path: " + options.url);
    }

    _.defer(function () {
      fakeResponse(resp);
    });
  }
};

TestingSupervisor.interceptAjax();
<|endoftext|>


<commit_before>/**
global boom config
@namespace
@name $.boom.config
*/

window.boomConfig = {
	/** @lends $.boom.config */

	/** @property */
	cachePageImages : [
		'/media/boom/img/ajax_load.gif',
		'/media/boom/img/cms/chunk_edit_icon.png'
	],

	/**
	@static
	@class
	*/
	cookie : {
		/**
		@type string
		@default 'boomcookie'
		*/
		name: 'boomcookie',
		/**
		@type string
		@default ','
		*/
		delimiter: ',',
		/**
		@type number
		@default 1
		*/
		expiredays: 1,
		/**
		@type string
		@default '/'
		*/
		path: '/'
	},

	/**
	@static
	@class
	*/
	logs : {
		/**
		@type boolean
		@default true
		*/
		show: false,
		/**
		@type boolean
		@default true
		*/
		showTimes: true,
		/**
		@type array
		@default []
		*/
		times: [],
		/**
		@type number
		@default 0
		*/
		totalTime: 0
	},

	/**
	@static
	@class
	*/
	errors : {
		/**
		@type boolean
		@default true
		*/
		report: true
	},

	/**
	@static
	@class
	*/
	history : {
		/**
		@type number
		@default 100
		*/
		checkInterval: 100
	},

	/**
	@static
	@class
	*/
	captions : {
		/**
		@type string
		@default '.caption'
		*/
		captionTitleSelector: '.caption',
		/**
		@type string
		@default '.caption-overlay'
		*/
	captionOverlaySelector: '.caption-overlay',
		/**
		@type number
		@default 0
		*/
		showSpeed: 0,
		/**
		@type number
		@default 0
		*/
		hideSpeed: 0,
		/**
		@type number
		@default 0.8
		*/
		opacityOverlay: 0.8
	},

	/**
	@static
	@class
	*/
	editor : {
		/**
		@type string
		@default '/boom/css/boom.page.edit.css'
		*/
		stylesheetURL: '/media/boom/js/xing/editor.css',

		/**
		@type string
		@default '/media/boom/js/boom.tinymce.js'
		*/
		path : '/media/boom/js/boom.wysihtml5.js'
	},

	/**
	@static
	@class
	*/
	dialog : {
		/**
		@type string
		@default 'auto'
		*/
		width: 'auto',
		/**
		@type number
		@default 100
		*/
		maxWidth: 100,
		/**
		@type
		@default null
		*/
		show: null,
		/**
		@type
		@default null
		*/
		hide: null,
		/**
		@type boolean
		@default true
		*/
		autoOpen: true,
		/**
		@type boolean
		@default true
		*/
		modal: true,
		/**
		@type boolean
		@default false
		*/
		resizable: false,
		/**
		@type array
		@default ['center', 'center']
		*/
		position: ['center', 'center'],
		/**
		@type boolean
		@default true
		*/
		draggable: true,
		/**
		@type boolean
		@default true
		*/
		closeOnEscape: true
	},

	/**
	@static
	@class
	*/
	growl : {
		/**
		@type string
		@default 'default'
		*/
		theme: 'default',
		/**
		@type number
		@default 240
		*/
		speed: 240,
		/**
		@type boolean
		@default false
		*/
		closer: false
	},

	/**
	@static
	@class
	*/
	datepicker : {
		/**
		@type boolean
		@default true
		*/
		mandatory: true,
		/**
		@type boolean
		@default true
		*/
		hideIfNoPrevNext: true,
		/**
		@type string
		@default 'fast'
		*/
		duration: 'fast',
		/**
		@type string
		@default 'fadeIn'
		*/
		showAnim: 'fadeIn',
		/**
		@type string
		@default 'dd MM yy'
		*/
		dateFormat: 'dd MM yy',
		/**
		@type boolean
		@default true
		*/
		showTime: true,
		/**
		@type string
		@default 'bottom'
		*/
		timePos: 'bottom'
	},

	/**
	@static
	@class
	*/
	tabs : {
		/**
		@type boolean
		@default false
		*/
		cache: false,
		/** @function */
		active: function(event, ui) {
			var url = $.data(ui.tab, 'load.tabs');
			if (url) {
				location.href = url;
				return false;
			}
			return true;
		},
		/** @function */
		activate: function(event, ui){
			//console.log( ui );
			//$(ui.tab.href.replace(/^.*?#/, '#')).show();
		}
	},

	/**
	@static
	@class
	*/
	tooltip : {
		/**
		@type object
		@param {string} my 'right left'
		@param {string} at 'left left'
		@param {string} offset '-5 0'
		*/
		position: {
                        my: 'right left',
			at: 'left left',
			offset: '-5 0'
		}
	},

	/**
	@static
	@class
	*/
	selectmenu : {
		/**
		@type number
		@default 200
		*/
		maxHeight: 200,
		/**
		@type string
		@default 'dropdown'
		*/
		style: 'dropdown',
		/**
		@type boolean
		@default true
		*/
		transferClasses: true,
		/**
		@type array
		@default [
			{ find: '.boom-selectmenu-page', icon: 'ui-icon-document' }
		]
		*/
		icons: [
			{ find: '.boom-selectmenu-page', icon: 'ui-icon-document' }
		]
	},

	/**
	@static
	@class
	*/
	tree : {
		/**
		@type boolean
		@default false
		*/
		parentAsFolder: false,
		/**
		@type boolean
		@default false
		*/
		icons: false,
		/**
		@type boolean
		@default false
		*/
		showEdit: false,
		/**
		@type boolean
		@default false
		*/
		showRemove: false,
		/**
		@type number
		@default -1
		*/
		maxSelected: -1,
		/**
		@type boolean
		@default false
		*/
		useCookie: false,
		/**
		@type boolean
		@default true
		*/
		toggleSelected: true,
		/**
		@type string
		@default 'auto'
		*/
		width: 'auto',
		/**
		@type string
		@default 'auto'
		*/
		height: 'auto',
		/**
		@type string
		@default 'boom-tree-hitarea-hover'
		*/
		iconHitareaHover: 'boom-tree-hitarea-hover'
	},

	/**
	@static
	@class
	*/
	sortable : {
		/**
		@type string
		@default 'parent'
		*/
		containment: 'parent',
		/**
		@type number
		@default 0.7
		*/
		opacity: 0.7,
		/**
		@type string
		@default 'y'
		*/
		axis: 'y'
	},

	/**
	@static
	@class
	*/
	uploadify : {
		/**
		@type boolean
		@default true
		*/
		debug: true,
		/**
		@type string
		@default '/boom/flash/uploadify.swf'
		*/
		swf: '/media/boom/flash/uploadify.swf',
		/**
		@type string
		@default '/cms/uploadify/asset'
		*/
		uploader: '/cms/uploadify/asset',
		/**
		@type boolean
		@default false
		*/
		auto: true,
		/**
		@type boolean
		@default true
		*/
		multi: true,
		/**
		@type string
		@default 'Select files'
		*/
		buttonText: 'Select files',
		/**
		@type number
		@default 5
		*/
		queueSizeLimit: 5,
		/**
		@type number
		@default 2
		*/
		simUploadLimit: 2,
		/**
		@type string
		@default 'Allowed types: jpg, png, gif'
		*/
		fileTypeDesc: 'Allowed types: jpg, png, gif',
		/**
		@type string
		@default '*.jpg;*.png;*.gif'
		*/
		fileTypeExts: '*.jpeg;*.jpg;*.png;*.gif',
		/**
		@type string
		@default '/boom/img/cms/cross.png'
		*/
		cancelImg: '/boom/img/cms/cross.png'
	},

	/**
	@static
	@class
	*/
	page : {
		/**
		@type number
		@default 1
		*/
		homepageRid: 1,
		/**
		@type number
		@default 0
		*/
		ajaxed: 0
	},

	/**
	@static
	@class
	*/
	ajax : {
		/**
		@type string
		@default '/_ajax/show_view/boom/editor/'
		*/
		viewBasePath: '/_ajax/show_view/boom/editor/'
	},

	/**
	@static
	@class
	*/
	person: {
		/**
		@type number
		@default 0
		*/
		rid: 0,
		/**
		@type string
		@default 'Default'
		*/
		firstname: 'Default',
		/**
		@type string
		@default ''
		*/
		lastname: ''
	}

};
<commit_msg>turn logging back on<commit_after>/**
global boom config
@namespace
@name $.boom.config
*/

window.boomConfig = {
	/** @lends $.boom.config */

	/** @property */
	cachePageImages : [
		'/media/boom/img/ajax_load.gif',
		'/media/boom/img/cms/chunk_edit_icon.png'
	],

	/**
	@static
	@class
	*/
	cookie : {
		/**
		@type string
		@default 'boomcookie'
		*/
		name: 'boomcookie',
		/**
		@type string
		@default ','
		*/
		delimiter: ',',
		/**
		@type number
		@default 1
		*/
		expiredays: 1,
		/**
		@type string
		@default '/'
		*/
		path: '/'
	},

	/**
	@static
	@class
	*/
	logs : {
		/**
		@type boolean
		@default true
		*/
		show: true,
		/**
		@type boolean
		@default true
		*/
		showTimes: true,
		/**
		@type array
		@default []
		*/
		times: [],
		/**
		@type number
		@default 0
		*/
		totalTime: 0
	},

	/**
	@static
	@class
	*/
	errors : {
		/**
		@type boolean
		@default true
		*/
		report: true
	},

	/**
	@static
	@class
	*/
	history : {
		/**
		@type number
		@default 100
		*/
		checkInterval: 100
	},

	/**
	@static
	@class
	*/
	captions : {
		/**
		@type string
		@default '.caption'
		*/
		captionTitleSelector: '.caption',
		/**
		@type string
		@default '.caption-overlay'
		*/
	captionOverlaySelector: '.caption-overlay',
		/**
		@type number
		@default 0
		*/
		showSpeed: 0,
		/**
		@type number
		@default 0
		*/
		hideSpeed: 0,
		/**
		@type number
		@default 0.8
		*/
		opacityOverlay: 0.8
	},

	/**
	@static
	@class
	*/
	editor : {
		/**
		@type string
		@default '/boom/css/boom.page.edit.css'
		*/
		stylesheetURL: '/media/boom/js/xing/editor.css',

		/**
		@type string
		@default '/media/boom/js/boom.tinymce.js'
		*/
		path : '/media/boom/js/boom.wysihtml5.js'
	},

	/**
	@static
	@class
	*/
	dialog : {
		/**
		@type string
		@default 'auto'
		*/
		width: 'auto',
		/**
		@type number
		@default 100
		*/
		maxWidth: 100,
		/**
		@type
		@default null
		*/
		show: null,
		/**
		@type
		@default null
		*/
		hide: null,
		/**
		@type boolean
		@default true
		*/
		autoOpen: true,
		/**
		@type boolean
		@default true
		*/
		modal: true,
		/**
		@type boolean
		@default false
		*/
		resizable: false,
		/**
		@type array
		@default ['center', 'center']
		*/
		position: ['center', 'center'],
		/**
		@type boolean
		@default true
		*/
		draggable: true,
		/**
		@type boolean
		@default true
		*/
		closeOnEscape: true
	},

	/**
	@static
	@class
	*/
	growl : {
		/**
		@type string
		@default 'default'
		*/
		theme: 'default',
		/**
		@type number
		@default 240
		*/
		speed: 240,
		/**
		@type boolean
		@default false
		*/
		closer: false
	},

	/**
	@static
	@class
	*/
	datepicker : {
		/**
		@type boolean
		@default true
		*/
		mandatory: true,
		/**
		@type boolean
		@default true
		*/
		hideIfNoPrevNext: true,
		/**
		@type string
		@default 'fast'
		*/
		duration: 'fast',
		/**
		@type string
		@default 'fadeIn'
		*/
		showAnim: 'fadeIn',
		/**
		@type string
		@default 'dd MM yy'
		*/
		dateFormat: 'dd MM yy',
		/**
		@type boolean
		@default true
		*/
		showTime: true,
		/**
		@type string
		@default 'bottom'
		*/
		timePos: 'bottom'
	},

	/**
	@static
	@class
	*/
	tabs : {
		/**
		@type boolean
		@default false
		*/
		cache: false,
		/** @function */
		active: function(event, ui) {
			var url = $.data(ui.tab, 'load.tabs');
			if (url) {
				location.href = url;
				return false;
			}
			return true;
		},
		/** @function */
		activate: function(event, ui){
			//console.log( ui );
			//$(ui.tab.href.replace(/^.*?#/, '#')).show();
		}
	},

	/**
	@static
	@class
	*/
	tooltip : {
		/**
		@type object
		@param {string} my 'right left'
		@param {string} at 'left left'
		@param {string} offset '-5 0'
		*/
		position: {
                        my: 'right left',
			at: 'left left',
			offset: '-5 0'
		}
	},

	/**
	@static
	@class
	*/
	selectmenu : {
		/**
		@type number
		@default 200
		*/
		maxHeight: 200,
		/**
		@type string
		@default 'dropdown'
		*/
		style: 'dropdown',
		/**
		@type boolean
		@default true
		*/
		transferClasses: true,
		/**
		@type array
		@default [
			{ find: '.boom-selectmenu-page', icon: 'ui-icon-document' }
		]
		*/
		icons: [
			{ find: '.boom-selectmenu-page', icon: 'ui-icon-document' }
		]
	},

	/**
	@static
	@class
	*/
	tree : {
		/**
		@type boolean
		@default false
		*/
		parentAsFolder: false,
		/**
		@type boolean
		@default false
		*/
		icons: false,
		/**
		@type boolean
		@default false
		*/
		showEdit: false,
		/**
		@type boolean
		@default false
		*/
		showRemove: false,
		/**
		@type number
		@default -1
		*/
		maxSelected: -1,
		/**
		@type boolean
		@default false
		*/
		useCookie: false,
		/**
		@type boolean
		@default true
		*/
		toggleSelected: true,
		/**
		@type string
		@default 'auto'
		*/
		width: 'auto',
		/**
		@type string
		@default 'auto'
		*/
		height: 'auto',
		/**
		@type string
		@default 'boom-tree-hitarea-hover'
		*/
		iconHitareaHover: 'boom-tree-hitarea-hover'
	},

	/**
	@static
	@class
	*/
	sortable : {
		/**
		@type string
		@default 'parent'
		*/
		containment: 'parent',
		/**
		@type number
		@default 0.7
		*/
		opacity: 0.7,
		/**
		@type string
		@default 'y'
		*/
		axis: 'y'
	},

	/**
	@static
	@class
	*/
	uploadify : {
		/**
		@type boolean
		@default true
		*/
		debug: true,
		/**
		@type string
		@default '/boom/flash/uploadify.swf'
		*/
		swf: '/media/boom/flash/uploadify.swf',
		/**
		@type string
		@default '/cms/uploadify/asset'
		*/
		uploader: '/cms/uploadify/asset',
		/**
		@type boolean
		@default false
		*/
		auto: true,
		/**
		@type boolean
		@default true
		*/
		multi: true,
		/**
		@type string
		@default 'Select files'
		*/
		buttonText: 'Select files',
		/**
		@type number
		@default 5
		*/
		queueSizeLimit: 5,
		/**
		@type number
		@default 2
		*/
		simUploadLimit: 2,
		/**
		@type string
		@default 'Allowed types: jpg, png, gif'
		*/
		fileTypeDesc: 'Allowed types: jpg, png, gif',
		/**
		@type string
		@default '*.jpg;*.png;*.gif'
		*/
		fileTypeExts: '*.jpeg;*.jpg;*.png;*.gif',
		/**
		@type string
		@default '/boom/img/cms/cross.png'
		*/
		cancelImg: '/boom/img/cms/cross.png'
	},

	/**
	@static
	@class
	*/
	page : {
		/**
		@type number
		@default 1
		*/
		homepageRid: 1,
		/**
		@type number
		@default 0
		*/
		ajaxed: 0
	},

	/**
	@static
	@class
	*/
	ajax : {
		/**
		@type string
		@default '/_ajax/show_view/boom/editor/'
		*/
		viewBasePath: '/_ajax/show_view/boom/editor/'
	},

	/**
	@static
	@class
	*/
	person: {
		/**
		@type number
		@default 0
		*/
		rid: 0,
		/**
		@type string
		@default 'Default'
		*/
		firstname: 'Default',
		/**
		@type string
		@default ''
		*/
		lastname: ''
	}

};
<|endoftext|>


<commit_before>'use strict';

var EventEmitter = require('eventemitter3')
  , listeners = require('loads')
  , AXO = require('axo');

/**
 * Optionally get a configuration value somewhere.
 *
 * @param {Object} options Optional configuration that needs default properties.
 * @api private
 */
function optional(options) {
  for (var key in Requests.defaults) {
    options[key] = key in options ? options[key] : Requests.defaults[key];
  }

  return options;
}

/**
 * RequestS(tream).
 *
 * Options:
 *
 * - streaming: Should the request be streaming.
 * - method: Which HTTP method should be used.
 * - headers: Additional request headers.
 * - mode: Enable CORS mode.
 * - body: The payload for the request.
 *
 * @constructor
 * @param {String} url The URL we want to request.
 * @param {Object} options Various of request options.
 * @api public
 */
function Requests(url, options) {
  if (!(this instanceof Requests)) return new Requests(url, options);
  options = optional(options || {});

  this.offset = 0;
  this.id = Requests.requested++;
  this.streaming = options.streaming;
  this.socket = Requests[Requests.method](options);
  this.socket.open(options.method.toUpperCase(), url, true);

  //
  // We want to implement a stream like interface on top of this module so it
  // can be used to read streaming data in node as well as through browserify.
  //
  this.readable = true;
  this.writable = false;

  //
  // Register this as an active HTTP request.
  //
  Requests.active[this.id] = this;
  this.initialize(options);
}

Requests.prototype = new EventEmitter();
Requests.prototype.constructor = Requests;

/**
 * Initialize and start requesting the supplied resource.
 *
 * @param {Object} options Passed in defaults.
 * @api private
 */
Requests.prototype.initialize = function initialize(options) {
  var what
    , requests = this
    , socket = requests.socket;

  this.on('stream', function stream(data) {
    if (socket.multipart) return this.emit('data', data);

    //
    // Please note that we need to use a method here that works on both string
    // as well as ArrayBuffer's as we have no certainty that we're receiving
    // text.
    //
    var chunk = data.slice(this.offset);
    this.offset = data.length;

    this.emit('data', chunk);
  });

  this.on('end', function cleanup() {
    delete Requests.active[this.id];
  });

  if (options.timeout) {
    socket.timeout = +options.time;
  }

  if ('cors' === options.mode.toLowerCase() && 'withCredentials' in socket) {
    socket.withCredentials = true;
  }

  //
  // We want to prevent pre-flight requests by default for CORS requests so we
  // need to force the content-type to text/plain.
  //
  this.header('Content-Type', 'text/plain');
  for (what in options.headers) {
    this.header(what, options.headers[what]);
  }

  //
  // Set the correct responseType method.
  //
  if (this.streaming) {
    if ('string' === typeof options.body) {
      if ('multipart' in socket) {
        socket.multipart = true;
      } else if (Requests.type.mozchunkedtext) {
        socket.responseType = 'moz-chunked-text';
      } else if (Requests.type.msstream) {
        socket.responseType = 'ms-stream';
      }
    } else {
      if (Requests.type.mozchunkedarraybuffer) {
        socket.responseType = 'moz-chunked-arraybuffer';
      }
    }
  }

  listeners(socket, this, this.streaming);
  socket.send(options.body);
};

/**
 * Safely set a request header.
 *
 * @param {String} key Name of the header.
 * @param {String} value Value of the header.
 * @returns {Requests}
 * @api public
 */
Requests.prototype.header = function header(key, value) {
  //
  // ActiveXObject will throw an `Type Mismatch` exception when setting the to
  // an null-value and to be consistent with all XHR implementations we're going
  // to cast the value to a string.
  //
  // While we don't technically support the XDomainRequest of IE, we do want to
  // double check that the setRequestHeader is available before adding headers.
  //
  if (value !== undefined && this.socket.setRequestHeader) {
    this.socket.setRequestHeader(key, value +'');
  }

  return this;
};

/**
 * Completely destroy the running XHR and release of the internal references.
 *
 * @returns {Boolean} Successful destruction
 * @api public
 */
Requests.prototype.destroy = function destroy() {
  if (!this.socket) return false;

  this.emit('destroy');

  this.socket.abort();
  this.removeAllListeners();

  this.socket = null;
  delete Requests.active[this.id];

  return true;
};

/**
 * Create a new XMLHttpRequest.
 *
 * @returns {XMLHttpRequest}
 * @api private
 */
Requests.XHR = function create() {
  try { return new XMLHttpRequest(); }
  catch (e) {}
};

/**
 * Create a new ActiveXObject which can be used for XHR.
 *
 * @returns {ActiveXObject}
 * @api private
 */
Requests.AXO = function create() {
  var ids = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', 'Microsoft.XMLHTTP']
    , id;

  while (ids.length) {
    id = ids.shift();

    try { return new AXO(id); }
    catch (e) {}
  }
};

/**
 * Requests that are currently running.
 *
 * @type {Object}
 * @private
 */
Requests.active = {};

/**
 * Unique id and also an indication on how many XHR requests we've made using
 * this library.
 *
 * @type {Number}
 * @private
 */
Requests.requested = 0;

/**
 * The type of technology we are using to establish a working Ajax connection.
 * This can either be:
 *
 * - XHR: XMLHttpRequest
 * - AXO: ActiveXObject
 *
 * This is also used as internal optimization so we can easily get the correct
 * constructor as we've already feature detected it.
 *
 * @type {String}
 * @public
 */
Requests.method = !!Requests.XHR() ? 'XHR' : (!!Requests.AXO() ? 'AXO' : '');

/**
 * Boolean indicating
 *
 * @type {Boolean}
 * @public
 */
Requests.supported = !!Requests.method;

/**
 * The defaults for the Requests. These values will be used if no options object
 * or matching key is provided. It can be override globally if needed but this
 * is not advised as it can have some potential side affects for other libraries
 * that use this module.
 *
 * @type {Object}
 * @public
 */
Requests.defaults = {
  streaming: false,
  method: 'GET',
  mode: 'cors',
  headers: {},
};

/**
 * The different type of `responseType` parsers that are supported in this XHR
 * implementation.
 *
 * @type {Object}
 * @public
 */
Requests.type = 'XHR' === Requests.method ? (function detect() {
  var types = 'arraybuffer,blob,document,json,text,moz-blob,moz-chunked-text,moz-chunked-arraybuffer,ms-stream'.split(',')
    , supported = {}
    , type, xhr, prop;

  while (types.length) {
    type = types.pop();

    xhr = Requests.XHR();
    xhr.open('get', '/', true);
    prop = type.replace(/-/g, '');

    //
    // We can only set the `responseType` after we've opened the connection or
    // FireFox will throw an error and according to the spec only async requests
    // can use this, which is fine as we force that by default.
    //
    try {
      xhr.responseType = type;
      supported[prop] = 'response' in xhr && xhr.responseType === type;
    } catch (e) {
      supported[prop] = false;
    }

    xhr = null;
  }

  return supported;
}()) : {};

/**
 * Do we support streaming response parsing.
 *
 * @type {Boolean}
 * @private
 */
Requests.streaming = 'XHR' === Requests.method && (
     'multipart' in XMLHttpRequest.prototype
  || Requests.type.mozchunkedarraybuffer
  || Requests.type.mozchunkedtext
  || Requests.type.msstream
  || Requests.type.mozblob
);

//
// Expose the Requests library.
//
module.exports = Requests;
<commit_msg>[fix] Prevent full browser freezes in IE10<commit_after>'use strict';

var EventEmitter = require('eventemitter3')
  , listeners = require('loads')
  , AXO = require('axo');

/**
 * Optionally get a configuration value somewhere.
 *
 * @param {Object} options Optional configuration that needs default properties.
 * @api private
 */
function optional(options) {
  for (var key in Requests.defaults) {
    options[key] = key in options ? options[key] : Requests.defaults[key];
  }

  return options;
}

/**
 * RequestS(tream).
 *
 * Options:
 *
 * - streaming: Should the request be streaming.
 * - method: Which HTTP method should be used.
 * - headers: Additional request headers.
 * - mode: Enable CORS mode.
 * - body: The payload for the request.
 *
 * @constructor
 * @param {String} url The URL we want to request.
 * @param {Object} options Various of request options.
 * @api public
 */
function Requests(url, options) {
  if (!(this instanceof Requests)) return new Requests(url, options);
  options = optional(options || {});

  this.offset = 0;
  this.id = Requests.requested++;
  this.streaming = options.streaming;
  this.socket = Requests[Requests.method](options);
  this.socket.open(options.method.toUpperCase(), url, true);

  //
  // We want to implement a stream like interface on top of this module so it
  // can be used to read streaming data in node as well as through browserify.
  //
  this.readable = true;
  this.writable = false;

  //
  // Register this as an active HTTP request.
  //
  Requests.active[this.id] = this;
  this.initialize(options);
}

Requests.prototype = new EventEmitter();
Requests.prototype.constructor = Requests;

/**
 * Initialize and start requesting the supplied resource.
 *
 * @param {Object} options Passed in defaults.
 * @api private
 */
Requests.prototype.initialize = function initialize(options) {
  var what
    , requests = this
    , socket = requests.socket;

  this.on('stream', function stream(data) {
    if (socket.multipart) return this.emit('data', data);

    //
    // Please note that we need to use a method here that works on both string
    // as well as ArrayBuffer's as we have no certainty that we're receiving
    // text.
    //
    var chunk = data.slice(this.offset);
    this.offset = data.length;

    this.emit('data', chunk);
  });

  this.on('end', function cleanup() {
    delete Requests.active[this.id];
  });

  if (options.timeout) {
    socket.timeout = +options.time;
  }

  if ('cors' === options.mode.toLowerCase() && 'withCredentials' in socket) {
    socket.withCredentials = true;
  }

  //
  // We want to prevent pre-flight requests by default for CORS requests so we
  // need to force the content-type to text/plain.
  //
  this.header('Content-Type', 'text/plain');
  for (what in options.headers) {
    this.header(what, options.headers[what]);
  }

  //
  // Set the correct responseType method.
  //
  if (this.streaming) {
    if ('string' === typeof options.body) {
      if ('multipart' in socket) {
        socket.multipart = true;
      } else if (Requests.type.mozchunkedtext) {
        socket.responseType = 'moz-chunked-text';
      } else if (Requests.type.msstream) {
        socket.responseType = 'ms-stream';
      }
    } else {
      if (Requests.type.mozchunkedarraybuffer) {
        socket.responseType = 'moz-chunked-arraybuffer';
      }
    }
  }

  listeners(socket, this, this.streaming);
  socket.send(options.body);
};

/**
 * Safely set a request header.
 *
 * @param {String} key Name of the header.
 * @param {String} value Value of the header.
 * @returns {Requests}
 * @api public
 */
Requests.prototype.header = function header(key, value) {
  //
  // ActiveXObject will throw an `Type Mismatch` exception when setting the to
  // an null-value and to be consistent with all XHR implementations we're going
  // to cast the value to a string.
  //
  // While we don't technically support the XDomainRequest of IE, we do want to
  // double check that the setRequestHeader is available before adding headers.
  //
  if (value !== undefined && this.socket.setRequestHeader) {
    this.socket.setRequestHeader(key, value +'');
  }

  return this;
};

/**
 * Completely destroy the running XHR and release of the internal references.
 *
 * @returns {Boolean} Successful destruction
 * @api public
 */
Requests.prototype.destroy = function destroy() {
  if (!this.socket) return false;

  this.emit('destroy');

  this.socket.abort();
  this.removeAllListeners();

  this.socket = null;
  delete Requests.active[this.id];

  return true;
};

/**
 * Create a new XMLHttpRequest.
 *
 * @returns {XMLHttpRequest}
 * @api private
 */
Requests.XHR = function create() {
  try { return new XMLHttpRequest(); }
  catch (e) {}
};

/**
 * Create a new ActiveXObject which can be used for XHR.
 *
 * @returns {ActiveXObject}
 * @api private
 */
Requests.AXO = function create() {
  var ids = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', 'Microsoft.XMLHTTP']
    , id;

  while (ids.length) {
    id = ids.shift();

    try { return new AXO(id); }
    catch (e) {}
  }
};

/**
 * Requests that are currently running.
 *
 * @type {Object}
 * @private
 */
Requests.active = {};

/**
 * Unique id and also an indication on how many XHR requests we've made using
 * this library.
 *
 * @type {Number}
 * @private
 */
Requests.requested = 0;

/**
 * The type of technology we are using to establish a working Ajax connection.
 * This can either be:
 *
 * - XHR: XMLHttpRequest
 * - AXO: ActiveXObject
 *
 * This is also used as internal optimization so we can easily get the correct
 * constructor as we've already feature detected it.
 *
 * @type {String}
 * @public
 */
Requests.method = !!Requests.XHR() ? 'XHR' : (!!Requests.AXO() ? 'AXO' : '');

/**
 * Boolean indicating
 *
 * @type {Boolean}
 * @public
 */
Requests.supported = !!Requests.method;

/**
 * The defaults for the Requests. These values will be used if no options object
 * or matching key is provided. It can be override globally if needed but this
 * is not advised as it can have some potential side affects for other libraries
 * that use this module.
 *
 * @type {Object}
 * @public
 */
Requests.defaults = {
  streaming: false,
  method: 'GET',
  mode: 'cors',
  headers: {},
};

/**
 * The different type of `responseType` parsers that are supported in this XHR
 * implementation.
 *
 * @type {Object}
 * @public
 */
Requests.type = 'XHR' === Requests.method ? (function detect() {
  var types = 'arraybuffer,blob,document,json,text,moz-blob,moz-chunked-text,moz-chunked-arraybuffer,ms-stream'.split(',')
    , supported = {}
    , type, xhr, prop;

  while (types.length) {
    type = types.pop();

    xhr = Requests.XHR();
    xhr.open('get', '/', true);
    prop = type.replace(/-/g, '');

    //
    // We can only set the `responseType` after we've opened the connection or
    // FireFox will throw an error and according to the spec only async requests
    // can use this, which is fine as we force that by default.
    //
    try {
      xhr.responseType = type;
      supported[prop] = 'response' in xhr && xhr.responseType === type;
    } catch (e) {
      supported[prop] = false;
    }

    xhr = null;
  }

  return supported;
}()) : {};

/**
 * Do we support streaming response parsing.
 *
 * @type {Boolean}
 * @private
 */
Requests.streaming = 'XHR' === Requests.method && (
     'multipart' in XMLHttpRequest.prototype
  || Requests.type.mozchunkedarraybuffer
  || Requests.type.mozchunkedtext
  || Requests.type.msstream
  || Requests.type.mozblob
);

//
// IE has a bug which causes IE10 to freeze when close WebPage during an XHR
// request: https://support.microsoft.com/kb/2856746
//
// The solution is to completely clean up all active running requests.
//
if (global.attachEvent) global.attachEvent('onunload', function reap() {
  for (var id in Requests.active) {
    Requests.active[id].destroy();
  }
});

//
// Expose the Requests library.
//
module.exports = Requests;
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
var config = require('../config');
require('../models/wallet');
require('../models/walletAddress');
require('../models/transaction');
require('../models/block');

var StorageService = function(){
};

StorageService.prototype.start = function(ready) {
  mongoose.connect('mongodb://' + config.dbHost + '/fullNodePlus?socketTimeoutMS=3600000&noDelay=true', {
    useMongoClient: true,
    keepAlive: 15,
    poolSize: config.maxPoolSize
  }, ready);
};

StorageService.prototype.stop = function() {

};

module.exports = new StorageService();<commit_msg>adding streaming find method for any model to cursor back to express response<commit_after>'use strict';
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
var config = require('../config');
require('../models/wallet');
require('../models/walletAddress');
require('../models/transaction');
require('../models/block');

var StorageService = function(){
};

StorageService.prototype.start = function(ready) {
  mongoose.connect('mongodb://' + config.dbHost + '/fullNodePlus?socketTimeoutMS=3600000&noDelay=true', {
    useMongoClient: true,
    keepAlive: 15,
    poolSize: config.maxPoolSize
  }, ready);
};

StorageService.prototype.stop = function() {

};

StorageService.prototype.apiStreamingFind = function(model,query,limit,params,res){
  var cursor = model.find(query).limit(limit).cursor({transform: model._apiTransform});
  cursor.on('error', function(err) {
    return res.status(500).end(err.message);
  });
  cursor.pipe(res.type('json'));
};

module.exports = new StorageService();<|endoftext|>


<commit_before>//
// Usage:
//
// var config = {
//     canvas: document.getElementById('myCanvas')
// };
//
// var data = {
//     labels: ["Jan", "Feb", "Mar"],
//     datasets: [
//         {
//             data: [3.5, 12.2, 6.8]
//         },
//         {
//             data: [5.4, 9.9, 4.6]
//         }
//     ]
// };
//
// new SlimChart(config).draw(data);
//
function SlimChart(config) {
    var self = this;

    //
    // Override these default configuration parameters yourself
    //
    self.initialize = function (config) {
        self.config = {
            canvas: config.canvas, // required - a canvas element
            axisLineWidth: config.axisLineWidth || 1,
            axisLineColor: config.axisLineColor || "#000000",
            axisTextColor: config.axisTextColor || "#000000",
            xAxisFormatter: config.xAxisFormatter || self.defaultXAxisFormatter,
            yAxisFormatter: config.yAxisFormatter || self.defaultYAxisFormatter,
            yAxisMin: config.yAxisMin,
            yAxisMax: config.yAxisMax,
            yAxisSteps: config.yAxisSteps || 5,
            datasetLineWidth: config.datasetLineWidth || 2,
            datasetColorPicker: config.datasetColorPicker || self.defaultColorPicker
        };

        if (self.config.canvas instanceof HTMLCanvasElement) {
            self.config.context = canvas.getContext('2d');
        } else {
            throw new Error("canvas is not an element");
        }
    };

    //
    // Draws (or redraws) the chart; this can safely be called again with new data
    //
    self.draw = function (data) {
        self.clear();
        self.validateData(data);

        var start = new Date().getTime();

        self.scaleForRetina();
        self.analyzeData(data);
        self.drawDatasets(data);
        self.drawAxes(data);

        var end = new Date().getTime();

        console.log("drawn in " + (end - start));
    };

    //
    // Analyzes chart data to compute maximum and minimum
    //
    self.analyzeData = function (data) {
        var config = self.config;
        var ctx = config.context;
        var w = ctx.canvas.clientWidth;
        var h = ctx.canvas.clientHeight;

        config.graphArea = {
            left: 50,
            top: 10,
            bottom: h - 50,
            right: w
        };

        if (typeof(config.yAxisMax) === 'undefined' || typeof(config.yAxisMin) === 'undefined') {
            var yAxisMax = Number.MIN_VALUE;
            var yAxisMin = Number.MAX_VALUE;

            data.datasets.forEach(function(dataset) {
                dataset.data.forEach(function(value) {
                    yAxisMax = Math.max(yAxisMax, value);
                    yAxisMin = Math.min(yAxisMin, value);
                });
            });

            if (typeof(config.yAxisMax) === 'undefined') {
                config.yAxisMax = yAxisMax;
            }

            if (typeof(config.yAxisMin) === 'undefined') {
                config.yAxisMin = yAxisMin;
            }

            config.yAxisMax = self.calculateYAxisCeiling(config.yAxisMax);
        }

        config.xStep = (config.graphArea.right - config.graphArea.left) / data.labels.length;
    };

    //
    // Draws the x-axis, y-axis, and labels
    //
    self.drawAxes = function (data) {
        var config = self.config;
        var ctx = config.context;
        var g = config.graphArea;

        ctx.translate(0.5, 0.5);
        ctx.lineWidth = config.axisLineWidth;
        ctx.strokeStyle = config.axisLineColor;
        ctx.beginPath();
        ctx.moveTo(g.left, g.top);
        ctx.lineTo(g.left, g.bottom);
        ctx.lineTo(g.right, g.bottom);
        ctx.stroke();
        ctx.fillStyle = config.axisTextColor;
        ctx.textBaseline = 'top';
        ctx.textAlign = 'center';

        for (var i = 0; i < data.labels.length; i++) {
            var x = Math.round(g.left + (config.xStep * i));
            var y = g.bottom;
            var t = config.xAxisFormatter(data.labels[i]);

            if (t) {
                ctx.beginPath();
                ctx.moveTo(x, y);
                ctx.lineTo(x, y + 5);
                ctx.stroke();

                ctx.fillText(t, x, y + 5);
            }
        }

        ctx.textBaseline = 'middle';
        ctx.textAlign = 'end';

        var yStep = (g.bottom - g.top) / config.yAxisSteps;

        for (var i = 0; i <= config.yAxisSteps; i++) {
            var x = g.left;
            var y = g.top + (i * yStep);
            var steps = config.yAxisSteps;
            var range = config.yAxisMax - config.yAxisMin;
            var v = config.yAxisMax - (i / config.yAxisSteps) * range;
            var t = config.yAxisFormatter(v, config.yAxisMax);

            ctx.beginPath();
            ctx.moveTo(x, y);
            ctx.lineTo(x - 5, y);
            ctx.stroke();

            ctx.fillText(t, x - 8, y);
        }

        ctx.translate(0, 0);
    };

    //
    // Draws a line showing values for each dataset
    //
    self.drawDatasets = function (data) {
        var config = self.config;
        var ctx = config.context;
        var g = config.graphArea;
        var width = g.right - g.left;
        var height = g.bottom - g.top;
        var range = config.yAxisMax - config.yAxisMin;

        data.datasets.forEach(function (dataset) {
            ctx.lineWidth = config.datasetLineWidth;
            ctx.strokeStyle = config.datasetColorPicker(dataset);
            ctx.beginPath();

            dataset.data.forEach(function (val, i) {
                var ratio = (val - config.yAxisMin) / (config.yAxisMax - config.yAxisMin);
                var x = g.left + (i * config.xStep);
                var y = g.bottom - (height * ratio);

                if (i == 0) {
                    ctx.moveTo(x, y);
                } else {
                    ctx.lineTo(x, y);
                }
            });

            ctx.stroke();
        });
    };

    //
    // Scales the canvas for retina devices
    //
    self.scaleForRetina = function () {
        var ctx = self.config.context;
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;

        if (window.devicePixelRatio) {
            ctx.canvas.style.width = width + "px";
            ctx.canvas.style.height = height + "px";
            ctx.canvas.height = height * window.devicePixelRatio;
            ctx.canvas.width = width * window.devicePixelRatio;
            ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
        }
    };

    //
    // Clears the canvas
    //
    self.clear = function () {
        self.config.context.clearRect(0, 0, self.config.canvas.width, self.config.canvas.height);
    };

    //
    // Calculates the graph ceiling for the y-axis (allowing for a nice round
    // number as the maximum)
    //
    self.calculateYAxisCeiling = function (value) {
        var steps = self.config.yAxisSteps;
        var magnitude = Math.floor(Math.log(value) / Math.LN10);
        var multiplier = Math.pow(10, magnitude);
        var stepSize = multiplier * Math.ceil(value / steps / multiplier);

        return stepSize * steps;
    };

    //
    // Validates the chart data has the bare minimum
    //
    self.validateData = function (data) {
        if (!data) {
            throw new Error("data is required");
        } else if (!Array.isArray(data.labels)) {
            throw new Error("data.labels must be an array");
        } else if (!Array.isArray(data.datasets)) {
            throw new Error("data.datasets must be an array");
        }
    };

    //
    // Default x-axis formatter that returns the literal value
    //
    self.defaultXAxisFormatter = function (val) {
        return val;
    };

    //
    // Default y-axis formatter that shows a reasonable amount of precision
    //
    self.defaultYAxisFormatter = function (value, max) {
        if (value == 0) {
            return "";
        } else if (max <= 0.1) {
            return value.toFixed(2);
        } else if (max <= 1) {
            return value.toFixed(1);
        } else if (max <= 10) {
            return value.toFixed(1);
        } else {
            return value.toFixed(0);
        }
    };

    //
    // Default color picker that picks a random color per dataset
    //
    self.defaultColorPicker = function (dataset) {
        return '#' + Math.floor(Math.random() * 16777215).toString(16);
    };

    self.initialize(config);
}
<commit_msg>Translate back to where we started.<commit_after>//
// Usage:
//
// var config = {
//     canvas: document.getElementById('myCanvas')
// };
//
// var data = {
//     labels: ["Jan", "Feb", "Mar"],
//     datasets: [
//         {
//             data: [3.5, 12.2, 6.8]
//         },
//         {
//             data: [5.4, 9.9, 4.6]
//         }
//     ]
// };
//
// new SlimChart(config).draw(data);
//
function SlimChart(config) {
    var self = this;

    //
    // Override these default configuration parameters yourself
    //
    self.initialize = function (config) {
        self.config = {
            canvas: config.canvas, // required - a canvas element
            axisLineWidth: config.axisLineWidth || 1,
            axisLineColor: config.axisLineColor || "#000000",
            axisTextColor: config.axisTextColor || "#000000",
            xAxisFormatter: config.xAxisFormatter || self.defaultXAxisFormatter,
            yAxisFormatter: config.yAxisFormatter || self.defaultYAxisFormatter,
            yAxisMin: config.yAxisMin,
            yAxisMax: config.yAxisMax,
            yAxisSteps: config.yAxisSteps || 5,
            datasetLineWidth: config.datasetLineWidth || 2,
            datasetColorPicker: config.datasetColorPicker || self.defaultColorPicker
        };

        if (self.config.canvas instanceof HTMLCanvasElement) {
            self.config.context = canvas.getContext('2d');
        } else {
            throw new Error("canvas is not an element");
        }
    };

    //
    // Draws (or redraws) the chart; this can safely be called again with new data
    //
    self.draw = function (data) {
        self.clear();
        self.validateData(data);

        var start = new Date().getTime();

        self.scaleForRetina();
        self.analyzeData(data);
        self.drawDatasets(data);
        self.drawAxes(data);

        var end = new Date().getTime();

        console.log("drawn in " + (end - start));
    };

    //
    // Analyzes chart data to compute maximum and minimum
    //
    self.analyzeData = function (data) {
        var config = self.config;
        var ctx = config.context;
        var w = ctx.canvas.clientWidth;
        var h = ctx.canvas.clientHeight;

        config.graphArea = {
            left: 50,
            top: 10,
            bottom: h - 50,
            right: w
        };

        if (typeof(config.yAxisMax) === 'undefined' || typeof(config.yAxisMin) === 'undefined') {
            var yAxisMax = Number.MIN_VALUE;
            var yAxisMin = Number.MAX_VALUE;

            data.datasets.forEach(function(dataset) {
                dataset.data.forEach(function(value) {
                    yAxisMax = Math.max(yAxisMax, value);
                    yAxisMin = Math.min(yAxisMin, value);
                });
            });

            if (typeof(config.yAxisMax) === 'undefined') {
                config.yAxisMax = yAxisMax;
            }

            if (typeof(config.yAxisMin) === 'undefined') {
                config.yAxisMin = yAxisMin;
            }

            config.yAxisMax = self.calculateYAxisCeiling(config.yAxisMax);
        }

        config.xStep = (config.graphArea.right - config.graphArea.left) / data.labels.length;
    };

    //
    // Draws the x-axis, y-axis, and labels
    //
    self.drawAxes = function (data) {
        var config = self.config;
        var ctx = config.context;
        var g = config.graphArea;

        ctx.translate(0.5, 0.5);
        ctx.lineWidth = config.axisLineWidth;
        ctx.strokeStyle = config.axisLineColor;
        ctx.beginPath();
        ctx.moveTo(g.left, g.top);
        ctx.lineTo(g.left, g.bottom);
        ctx.lineTo(g.right, g.bottom);
        ctx.stroke();
        ctx.fillStyle = config.axisTextColor;
        ctx.textBaseline = 'top';
        ctx.textAlign = 'center';

        for (var i = 0; i < data.labels.length; i++) {
            var x = Math.round(g.left + (config.xStep * i));
            var y = g.bottom;
            var t = config.xAxisFormatter(data.labels[i]);

            if (t) {
                ctx.beginPath();
                ctx.moveTo(x, y);
                ctx.lineTo(x, y + 5);
                ctx.stroke();

                ctx.fillText(t, x, y + 5);
            }
        }

        ctx.textBaseline = 'middle';
        ctx.textAlign = 'end';

        var yStep = (g.bottom - g.top) / config.yAxisSteps;

        for (var i = 0; i <= config.yAxisSteps; i++) {
            var x = g.left;
            var y = g.top + (i * yStep);
            var steps = config.yAxisSteps;
            var range = config.yAxisMax - config.yAxisMin;
            var v = config.yAxisMax - (i / config.yAxisSteps) * range;
            var t = config.yAxisFormatter(v, config.yAxisMax);

            ctx.beginPath();
            ctx.moveTo(x, y);
            ctx.lineTo(x - 5, y);
            ctx.stroke();

            ctx.fillText(t, x - 8, y);
        }

        ctx.translate(-0.5, -0.5);
    };

    //
    // Draws a line showing values for each dataset
    //
    self.drawDatasets = function (data) {
        var config = self.config;
        var ctx = config.context;
        var g = config.graphArea;
        var width = g.right - g.left;
        var height = g.bottom - g.top;
        var range = config.yAxisMax - config.yAxisMin;

        data.datasets.forEach(function (dataset) {
            ctx.lineWidth = config.datasetLineWidth;
            ctx.strokeStyle = config.datasetColorPicker(dataset);
            ctx.beginPath();

            dataset.data.forEach(function (val, i) {
                var ratio = (val - config.yAxisMin) / (config.yAxisMax - config.yAxisMin);
                var x = g.left + (i * config.xStep);
                var y = g.bottom - (height * ratio);

                if (i == 0) {
                    ctx.moveTo(x, y);
                } else {
                    ctx.lineTo(x, y);
                }
            });

            ctx.stroke();
        });
    };

    //
    // Scales the canvas for retina devices
    //
    self.scaleForRetina = function () {
        var ctx = self.config.context;
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;

        if (window.devicePixelRatio) {
            ctx.canvas.style.width = width + "px";
            ctx.canvas.style.height = height + "px";
            ctx.canvas.height = height * window.devicePixelRatio;
            ctx.canvas.width = width * window.devicePixelRatio;
            ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
        }
    };

    //
    // Clears the canvas
    //
    self.clear = function () {
        self.config.context.clearRect(0, 0, self.config.canvas.width, self.config.canvas.height);
    };

    //
    // Calculates the graph ceiling for the y-axis (allowing for a nice round
    // number as the maximum)
    //
    self.calculateYAxisCeiling = function (value) {
        var steps = self.config.yAxisSteps;
        var magnitude = Math.floor(Math.log(value) / Math.LN10);
        var multiplier = Math.pow(10, magnitude);
        var stepSize = multiplier * Math.ceil(value / steps / multiplier);

        return stepSize * steps;
    };

    //
    // Validates the chart data has the bare minimum
    //
    self.validateData = function (data) {
        if (!data) {
            throw new Error("data is required");
        } else if (!Array.isArray(data.labels)) {
            throw new Error("data.labels must be an array");
        } else if (!Array.isArray(data.datasets)) {
            throw new Error("data.datasets must be an array");
        }
    };

    //
    // Default x-axis formatter that returns the literal value
    //
    self.defaultXAxisFormatter = function (val) {
        return val;
    };

    //
    // Default y-axis formatter that shows a reasonable amount of precision
    //
    self.defaultYAxisFormatter = function (value, max) {
        if (value == 0) {
            return "";
        } else if (max <= 0.1) {
            return value.toFixed(2);
        } else if (max <= 1) {
            return value.toFixed(1);
        } else if (max <= 10) {
            return value.toFixed(1);
        } else {
            return value.toFixed(0);
        }
    };

    //
    // Default color picker that picks a random color per dataset
    //
    self.defaultColorPicker = function (dataset) {
        return '#' + Math.floor(Math.random() * 16777215).toString(16);
    };

    self.initialize(config);
}
<|endoftext|>


<commit_before>/*
 * Own functions
 *
 */

/*
 * Define an own widget, which is basically an autocompleter that groups
 * results by category
 */
$.widget( "custom.catcomplete", $.ui.autocomplete, {
        _renderMenu: function( ul, items ) {
            var that = this,
                currentCategory = "";
            $.each( items, function( index, item ) {
                if ( item.category != currentCategory ) {
                    ul.append( "
" + item.category + "
" );
                    currentCategory = item.category;
                }
                that._renderItemData( ul, item );
            });
        }
    });

/*
 * Setup JQuery sortables to make the sets sortable
 */
function setup_sortable()
{
    // Hide the edit options for the set, this is done with the in-place editing
    $(".set-options").hide();

    $(".workout-table tbody").sortable({
        handle: '.dragndrop-handle',
        revert: true,
        update : function (event, ui) {
                // Monkey around the HTML, till we find the IDs of the set and the day
                var day_element = ui.item.parent().parent().find('tr').first().attr('id'); //day-xy
                var day_id = day_element.match(/\d+/);

                // returns something in the form "set-1,set-2,set-3,"
                var order = $( this ).sortable('toArray');

                //$("#ajax-info").show();
                //$("#ajax-info").addClass('success');
                $.get("/workout/api/edit-set" + "?do=set_order&day_id=" + day_id + "&order=" + order)

                // TODO: it seems to be necessary to call the view two times before it returns
                //       current data.
                $.get("/workout/day/view/" + day_id);
                $("#div-day-" + day_id).load("/workout/day/view/" + day_id);
        }

    })

    // Allow the settings within an exercise to be sortable
    $(".settings-list").sortable({
        placeholder: 'sortable-settings',
        revert: true,
        tolerance: 'pointer',
        helper: function(event, ui) {
            //return ui;
            return $('
' + ui.html() + '
');
        },
        update : function (event, ui) {
            // returns something in the form "setting-1,setting-2,setting-3,"
            var order = $( this ).sortable('toArray');

            // Load the day-ID
            var day_element = ui.item.parents('table').find('tr').attr('id'); //day-xy
            var day_id = day_element.match(/\d+/);

            //$("#ajax-info").show();
            //$("#ajax-info").addClass('success');
            $("#ajax-info").load("/workout/api/edit-settting?do=set_order&order=" + order);

            // TODO: it seems to be necessary to call the view two times before it returns
            //       current data.
            $.get("/workout/day/view/" + day_id);
            $("#div-day-" + day_id).load("/workout/day/view/" + day_id);
        }
    });
}

/*
 * Setup JQuery calls to edit the sets
 */
function setup_ajax_set_edit()
{
    // Unbind all other click events so we don't do this more than once
    $(".ajax-set-edit").off();

    $(".ajax-set-edit").click(function(e) {
        e.preventDefault();

        var set_id = $(this).parents('tr').attr('id').match(/\d+/);
        var exercise_id = $(this).parents('.ajax-set-edit-target').attr('id').match(/\d+/);

        load_edit_set($(this).parents('.ajax-set-edit-target'), set_id, exercise_id)
    });
}

function load_edit_set(element, set_id, exercise_id)
{
    $(element).load("/workout/api/edit-set?do=edit_set&set=" + set_id + "&exercise=" + exercise_id);
}

function setup_inplace_editing()
{
    $(".ajax-form-cancel").each(function(index, element) {

        var exercise_id = $(this).parents('.ajax-set-edit-target').attr('id').match(/\d+/);
        var day_id = $(this).parents('table').attr('id').match(/\d+/);
        var set_id = $(this).parents('tr').attr('id').match(/\d+/);

        // Editing of set
        $(element).click(function(e) {
            e.preventDefault();
            $("#div-day-" + day_id).load("/workout/day/view/" + day_id);
        })

        // Send the Form
        $('.ajax-form-set-edit').submit(function(e) {
          e.preventDefault();

          url = "/workout/api/edit-set?do=edit_set&set=" + set_id + "&exercise=" + exercise_id
          form_data = $(this).serialize();
          $.post( url, form_data);

          $("#div-day-" + day_id).load("/workout/day/view/" + day_id);
        });

        // Init the autocompleter
        $(".ajax-form-exercise-list").catcomplete({
                source: "/exercise/search/",
                minLength: 2,
                select: function(event, ui) {

                    // After clicking on a result set the value of the hidden field
                    $('#set-' + set_id + '-exercercise-id-hidden').val(ui.item.id);
                }
            });
    });
}

/*
 *
 * Functions related to the user's preferences
 *
 */
function toggle_comments()
{
    $("#exercise-comments-toggle").click(function(e) {
        e.preventDefault();

        if ( showComment == 0 )
        {
            $('.exercise-comments').show();
            showComment = 1;
        }
        else if ( showComment == 1 )
        {
            $('.exercise-comments').hide();
            showComment = 0;
        }

        $("#ajax-info").load("/workout/api/user-preferences?do=set_show-comments&show=" + showComment);
    });
}

function set_english_ingredients()
{
    $("#ajax-english-ingredients").click(function(e) {
        e.preventDefault();

        if ( useEnglishIngredients == 0 )
        {
            $('#english-ingredients-status').attr("src", "/static/images/icons/status-on.svg");
            useEnglishIngredients = 1;
        }
        else if ( useEnglishIngredients == 1 )
        {
             $('#english-ingredients-status').attr("src", "/static/images/icons/status-off.svg");
             useEnglishIngredients = 0;
        }

        $("#ajax-info").load("/workout/api/user-preferences?do=set_english-ingredients&show=" + useEnglishIngredients);
    });
}

/*
 * Init calls for tinyMCE editor
 */
function init_tinymce () {

    // Only try to init it on pages that loaded its JS file (so they probably need it)
    if (typeof tinyMCE != 'undefined')
    {
        tinyMCE.init({
            // General options
            mode : "textareas",
            theme : "simple",
            width : "100%",
            height : "200"
        });
   }
}

/*
 * Open a modal dialog for editing
 */
function form_modal_dialog()
{
    // Initialise a modal dialog
    $("#ajax-info").dialog({
                autoOpen: false,
                width: 600,
                modal: true,
                position: 'top'
    });

    // Unbind all other click events so we don't do this more than once
    $(".modal-dialog").off();

    // Load the edit dialog when the user clicks on an edit link
    $(".modal-dialog").click(function(e) {
        e.preventDefault();
        var targetUrl = $(this).attr("href");

        // Show a loader while we fetch the real page
        $("#ajax-info").html('
'+
                                ' ' +
                             '
');
        $("#ajax-info").dialog({title: 'Loading...'});
        $("#ajax-info").dialog("open");

        $("#ajax-info").load(targetUrl + " .ym-form", function(responseText, textStatus) {
            // Call other custom initialisation functions
            // (e.g. if the form as an autocompleter, it has to be initialised again)
            if (typeof custom_modal_init != "undefined")
            {
                custom_modal_init();
            }

            // Set its title and open the dialog
            $("#ajax-info").dialog({title: $(responseText).find("#main-content h2").html()});
            //$("#ajax-info").dialog("open");
        });
    });
}

function scatterplot_modal_dialog(id)
{
        var targetUrl = '/weight/' + id + '/edit/'

        $("#ajax-info").load(targetUrl + " .ym-form", function(responseText, textStatus) {

            // Set the title and open the dialog
            $("#ajax-info").dialog({title: $(responseText).find("#main-content h2").html()});
            $("#ajax-info").dialog("open");

            // Initialise the datepicker for the modal dialog
            init_weight_datepicker();
        });
}

function init_ingredient_autocompleter()
{
    // Init the autocompleter
    $("#id_ingredient_searchfield").autocomplete({
        source: "/nutrition/ingredient/search/",
        minLength: 2,
        select: function(event, ui) {

            // After clicking on a result set the value of the hidden field
            $('#id_ingredient').val(ui.item.id);
        }
    });
}

/*
 * Returns a random hex string. This is useful, e.g. to add a unique ID to generated
 * HTML elements
 */
function hex_random()
{
    return Math.floor(
        Math.random() * 0x10000 /* 65536 */
    ).toString(16);
}

/*
 * Template-like function that adds form elements to the ajax exercise selection
 * in the edit set page
 */
function add_exercise(exercise)
{
    var result_div = '
 \
 \
 \
 EXERCISE \
<input type="hidden" name="exercises" value="EXCERCISE-ID"> \

';

    // Replace the values into the 'template'
    result_div = result_div.replace('DIV-ID', hex_random());
    result_div = result_div.replace('EXERCISE', exercise.value);
    result_div = result_div.replace('EXCERCISE-ID', exercise.id);

    $(result_div).prependTo("#exercise-search-log");
    $("#exercise-search-log").scrollTop(0);
}

function init_edit_set()
{
    // Validate the form with JQuery
    $(".ym-form").validate({
                    errorClass:'form-error',
                    rules: {
                        sets: {
                            required: true,
                            number: true,
                            max: 6
                        }
                    }

                    });

    // The multi-select exercise list is not needed if javascript is activated
    $('#form-exercises').remove();

    // Initialise the autocompleter (our widget, defined above)
    $("#exercise-search").catcomplete({
            source: "/exercise/search/",
            minLength: 2,
            select: function(event, ui) {

                // Add the exercise to the list
                add_exercise(ui.item);

                // Remove the result div (also contains the hidden form element) when the user
                // clicks on the delete link
                $(".ajax-exercise-select a").click(function(e) {
                    e.preventDefault();
                    $(this).parent('div').remove();
                });

                // Reset the autocompleter
                $(this).val("");
                return false;
            }
        });
}

function init_weight_datepicker()
{
    $( "#id_creation_date" ).datepicker({ dateFormat: "yy-mm-dd" });
}

/*
 *
 * D3js functions
 *
 */
// Simple helper function that simply returns the y component of an entry
function y_value(d) { return d.y; }

function getDate(d) {
    return new Date(d);
}

function weight_chart(data)
{
    // Return if there is no data to process
    if(data == '')
    {
        return;
    }

    var minDate = getDate(data[0].x),
        maxDate = getDate(data[data.length-1].x);

    var margin = {top: 10, right: 10, bottom: 20, left: 40},
        width = 600 - margin.left - margin.right,
        height = 300 - margin.top - margin.bottom;

    var x = d3.time.scale()
        .domain([minDate, maxDate])
        .range([0, width]);

    var min_y_value = d3.min(data, y_value) - 1;
    var max_y_value = d3.max(data, y_value) + 1;

    var y = d3.scale.linear()
        .domain([min_y_value, max_y_value])
        .range([height, 0]);

    var xAxis = d3.svg.axis()
        .scale(x)
        .ticks(6)
        .orient("bottom");

    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left");

    var line = d3.svg.line()
        .x(function(d) { return x(getDate(d.x)); })
        .y(function(d) { return y(d.y); })
        .interpolate('cardinal');

    var area = d3.svg.area()
        .x(line.x())
        .y1(line.y())
        .y0(y(min_y_value))
        .interpolate('cardinal');

    // Reset the content of weight_diagram, otherwise if there is a filter
    // a new SVG will be appended to it
    $("#weight_diagram").html("");

    var svg = d3.select("#weight_diagram").append("svg")
        .datum(data)
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    svg.append("path")
        .attr("class", "area")
        .attr("d", area);

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

    svg.append("path")
        .attr("class", "line")
        .attr("d", line);

    svg.selectAll(".dot")
        .data(data.filter(function(d) { return d.y; }))
      .enter().append("circle")
        .attr("class", "dot")
        .attr("id", function(d) { return d.id; })
        .attr("cx", line.x())
        .attr("cy", line.y())
        .attr("r", 5);

    // Make the circles clickable: open their edit dialog
    $('circle').click(function(e) {
            entry_id = $(this).attr('id').match(/\d+/);
            scatterplot_modal_dialog(entry_id);
        });
}

/*
 *
 * Helper function to load the target of a link into the main-content DIV (the
 * main left colum)
 *
 */
function load_maincontent()
{
    // TODO: see what can be done about browser history and current URL
    $(".load-maincontent").click(function(e) {
        e.preventDefault();
        var targetUrl = $(this).attr("href");

        $.get(targetUrl, function(data) {
            $('#main-content').html($(data).find('#main-content').html());
            load_maincontent();
        });
    });
}
<commit_msg>Also show a loader when edting existing weight entries<commit_after>/*
 * Own functions
 *
 */

/*
 * Define an own widget, which is basically an autocompleter that groups
 * results by category
 */
$.widget( "custom.catcomplete", $.ui.autocomplete, {
        _renderMenu: function( ul, items ) {
            var that = this,
                currentCategory = "";
            $.each( items, function( index, item ) {
                if ( item.category != currentCategory ) {
                    ul.append( "
" + item.category + "
" );
                    currentCategory = item.category;
                }
                that._renderItemData( ul, item );
            });
        }
    });

/*
 * Setup JQuery sortables to make the sets sortable
 */
function setup_sortable()
{
    // Hide the edit options for the set, this is done with the in-place editing
    $(".set-options").hide();

    $(".workout-table tbody").sortable({
        handle: '.dragndrop-handle',
        revert: true,
        update : function (event, ui) {
                // Monkey around the HTML, till we find the IDs of the set and the day
                var day_element = ui.item.parent().parent().find('tr').first().attr('id'); //day-xy
                var day_id = day_element.match(/\d+/);

                // returns something in the form "set-1,set-2,set-3,"
                var order = $( this ).sortable('toArray');

                //$("#ajax-info").show();
                //$("#ajax-info").addClass('success');
                $.get("/workout/api/edit-set" + "?do=set_order&day_id=" + day_id + "&order=" + order)

                // TODO: it seems to be necessary to call the view two times before it returns
                //       current data.
                $.get("/workout/day/view/" + day_id);
                $("#div-day-" + day_id).load("/workout/day/view/" + day_id);
        }

    })

    // Allow the settings within an exercise to be sortable
    $(".settings-list").sortable({
        placeholder: 'sortable-settings',
        revert: true,
        tolerance: 'pointer',
        helper: function(event, ui) {
            //return ui;
            return $('
' + ui.html() + '
');
        },
        update : function (event, ui) {
            // returns something in the form "setting-1,setting-2,setting-3,"
            var order = $( this ).sortable('toArray');

            // Load the day-ID
            var day_element = ui.item.parents('table').find('tr').attr('id'); //day-xy
            var day_id = day_element.match(/\d+/);

            //$("#ajax-info").show();
            //$("#ajax-info").addClass('success');
            $("#ajax-info").load("/workout/api/edit-settting?do=set_order&order=" + order);

            // TODO: it seems to be necessary to call the view two times before it returns
            //       current data.
            $.get("/workout/day/view/" + day_id);
            $("#div-day-" + day_id).load("/workout/day/view/" + day_id);
        }
    });
}

/*
 * Setup JQuery calls to edit the sets
 */
function setup_ajax_set_edit()
{
    // Unbind all other click events so we don't do this more than once
    $(".ajax-set-edit").off();

    $(".ajax-set-edit").click(function(e) {
        e.preventDefault();

        var set_id = $(this).parents('tr').attr('id').match(/\d+/);
        var exercise_id = $(this).parents('.ajax-set-edit-target').attr('id').match(/\d+/);

        load_edit_set($(this).parents('.ajax-set-edit-target'), set_id, exercise_id)
    });
}

function load_edit_set(element, set_id, exercise_id)
{
    $(element).load("/workout/api/edit-set?do=edit_set&set=" + set_id + "&exercise=" + exercise_id);
}

function setup_inplace_editing()
{
    $(".ajax-form-cancel").each(function(index, element) {

        var exercise_id = $(this).parents('.ajax-set-edit-target').attr('id').match(/\d+/);
        var day_id = $(this).parents('table').attr('id').match(/\d+/);
        var set_id = $(this).parents('tr').attr('id').match(/\d+/);

        // Editing of set
        $(element).click(function(e) {
            e.preventDefault();
            $("#div-day-" + day_id).load("/workout/day/view/" + day_id);
        })

        // Send the Form
        $('.ajax-form-set-edit').submit(function(e) {
          e.preventDefault();

          url = "/workout/api/edit-set?do=edit_set&set=" + set_id + "&exercise=" + exercise_id
          form_data = $(this).serialize();
          $.post( url, form_data);

          $("#div-day-" + day_id).load("/workout/day/view/" + day_id);
        });

        // Init the autocompleter
        $(".ajax-form-exercise-list").catcomplete({
                source: "/exercise/search/",
                minLength: 2,
                select: function(event, ui) {

                    // After clicking on a result set the value of the hidden field
                    $('#set-' + set_id + '-exercercise-id-hidden').val(ui.item.id);
                }
            });
    });
}

/*
 *
 * Functions related to the user's preferences
 *
 */
function toggle_comments()
{
    $("#exercise-comments-toggle").click(function(e) {
        e.preventDefault();

        if ( showComment == 0 )
        {
            $('.exercise-comments').show();
            showComment = 1;
        }
        else if ( showComment == 1 )
        {
            $('.exercise-comments').hide();
            showComment = 0;
        }

        $("#ajax-info").load("/workout/api/user-preferences?do=set_show-comments&show=" + showComment);
    });
}

function set_english_ingredients()
{
    $("#ajax-english-ingredients").click(function(e) {
        e.preventDefault();

        if ( useEnglishIngredients == 0 )
        {
            $('#english-ingredients-status').attr("src", "/static/images/icons/status-on.svg");
            useEnglishIngredients = 1;
        }
        else if ( useEnglishIngredients == 1 )
        {
             $('#english-ingredients-status').attr("src", "/static/images/icons/status-off.svg");
             useEnglishIngredients = 0;
        }

        $("#ajax-info").load("/workout/api/user-preferences?do=set_english-ingredients&show=" + useEnglishIngredients);
    });
}

/*
 * Init calls for tinyMCE editor
 */
function init_tinymce () {

    // Only try to init it on pages that loaded its JS file (so they probably need it)
    if (typeof tinyMCE != 'undefined')
    {
        tinyMCE.init({
            // General options
            mode : "textareas",
            theme : "simple",
            width : "100%",
            height : "200"
        });
   }
}

/*
 * Open a modal dialog for form editing
 */
function form_modal_dialog()
{
    // Initialise a modal dialog
    $("#ajax-info").dialog({
                autoOpen: false,
                width: 600,
                modal: true,
                position: 'top'
    });

    // Unbind all other click events so we don't do this more than once
    $(".modal-dialog").off();

    // Load the edit dialog when the user clicks on an edit link
    $(".modal-dialog").click(function(e) {
        e.preventDefault();
        var targetUrl = $(this).attr("href");

        // Show a loader while we fetch the real page
        $("#ajax-info").html('
'+
                                ' ' +
                             '
');
        $("#ajax-info").dialog({title: 'Loading...'});
        $("#ajax-info").dialog("open");

        $("#ajax-info").load(targetUrl + " .ym-form", function(responseText, textStatus) {
            // Call other custom initialisation functions
            // (e.g. if the form as an autocompleter, it has to be initialised again)
            if (typeof custom_modal_init != "undefined")
            {
                custom_modal_init();
            }

            // Set the new title
            $("#ajax-info").dialog({title: $(responseText).find("#main-content h2").html()});
        });
    });
}

/*
 * Open a modal dialog for editing weight entries from the weight chart
 */
function scatterplot_modal_dialog(id)
{
        var targetUrl = '/weight/' + id + '/edit/'

        $("#ajax-info").load(targetUrl + " .ym-form", function(responseText, textStatus) {

            // Set the new title
            $("#ajax-info").dialog({title: $(responseText).find("#main-content h2").html()});

            // Initialise the datepicker for the modal dialog
            init_weight_datepicker();
        });
}

function init_ingredient_autocompleter()
{
    // Init the autocompleter
    $("#id_ingredient_searchfield").autocomplete({
        source: "/nutrition/ingredient/search/",
        minLength: 2,
        select: function(event, ui) {

            // After clicking on a result set the value of the hidden field
            $('#id_ingredient').val(ui.item.id);
        }
    });
}

/*
 * Returns a random hex string. This is useful, e.g. to add a unique ID to generated
 * HTML elements
 */
function hex_random()
{
    return Math.floor(
        Math.random() * 0x10000 /* 65536 */
    ).toString(16);
}

/*
 * Template-like function that adds form elements to the ajax exercise selection
 * in the edit set page
 */
function add_exercise(exercise)
{
    var result_div = '
 \
 \
 \
 EXERCISE \
<input type="hidden" name="exercises" value="EXCERCISE-ID"> \

';

    // Replace the values into the 'template'
    result_div = result_div.replace('DIV-ID', hex_random());
    result_div = result_div.replace('EXERCISE', exercise.value);
    result_div = result_div.replace('EXCERCISE-ID', exercise.id);

    $(result_div).prependTo("#exercise-search-log");
    $("#exercise-search-log").scrollTop(0);
}

function init_edit_set()
{
    // Validate the form with JQuery
    $(".ym-form").validate({
                    errorClass:'form-error',
                    rules: {
                        sets: {
                            required: true,
                            number: true,
                            max: 6
                        }
                    }

                    });

    // The multi-select exercise list is not needed if javascript is activated
    $('#form-exercises').remove();

    // Initialise the autocompleter (our widget, defined above)
    $("#exercise-search").catcomplete({
            source: "/exercise/search/",
            minLength: 2,
            select: function(event, ui) {

                // Add the exercise to the list
                add_exercise(ui.item);

                // Remove the result div (also contains the hidden form element) when the user
                // clicks on the delete link
                $(".ajax-exercise-select a").click(function(e) {
                    e.preventDefault();
                    $(this).parent('div').remove();
                });

                // Reset the autocompleter
                $(this).val("");
                return false;
            }
        });
}

function init_weight_datepicker()
{
    $( "#id_creation_date" ).datepicker({ dateFormat: "yy-mm-dd" });
}

/*
 *
 * D3js functions
 *
 */
// Simple helper function that simply returns the y component of an entry
function y_value(d) { return d.y; }

function getDate(d) {
    return new Date(d);
}

function weight_chart(data)
{
    // Return if there is no data to process
    if(data == '')
    {
        return;
    }

    var minDate = getDate(data[0].x),
        maxDate = getDate(data[data.length-1].x);

    var margin = {top: 10, right: 10, bottom: 20, left: 40},
        width = 600 - margin.left - margin.right,
        height = 300 - margin.top - margin.bottom;

    var x = d3.time.scale()
        .domain([minDate, maxDate])
        .range([0, width]);

    var min_y_value = d3.min(data, y_value) - 1;
    var max_y_value = d3.max(data, y_value) + 1;

    var y = d3.scale.linear()
        .domain([min_y_value, max_y_value])
        .range([height, 0]);

    var xAxis = d3.svg.axis()
        .scale(x)
        .ticks(6)
        .orient("bottom");

    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left");

    var line = d3.svg.line()
        .x(function(d) { return x(getDate(d.x)); })
        .y(function(d) { return y(d.y); })
        .interpolate('cardinal');

    var area = d3.svg.area()
        .x(line.x())
        .y1(line.y())
        .y0(y(min_y_value))
        .interpolate('cardinal');

    // Reset the content of weight_diagram, otherwise if there is a filter
    // a new SVG will be appended to it
    $("#weight_diagram").html("");

    var svg = d3.select("#weight_diagram").append("svg")
        .datum(data)
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    svg.append("path")
        .attr("class", "area")
        .attr("d", area);

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

    svg.append("path")
        .attr("class", "line")
        .attr("d", line);

    svg.selectAll(".dot")
        .data(data.filter(function(d) { return d.y; }))
      .enter().append("circle")
        .attr("class", "dot")
        .attr("id", function(d) { return d.id; })
        .attr("cx", line.x())
        .attr("cy", line.y())
        .attr("r", 5);

    // Make the circles clickable: open their edit dialog
    $('circle').click(function(e) {
            $("#ajax-info").html('
'+
                                ' ' +
                             '
');
            $("#ajax-info").dialog({title: 'Loading...'});
            $("#ajax-info").dialog("open");

            entry_id = $(this).attr('id').match(/\d+/);
            scatterplot_modal_dialog(entry_id);
        });
}

/*
 *
 * Helper function to load the target of a link into the main-content DIV (the
 * main left colum)
 *
 */
function load_maincontent()
{
    // TODO: see what can be done about browser history and current URL
    $(".load-maincontent").click(function(e) {
        e.preventDefault();
        var targetUrl = $(this).attr("href");

        $.get(targetUrl, function(data) {
            $('#main-content').html($(data).find('#main-content').html());
            load_maincontent();
        });
    });
}
<|endoftext|>