<commit_before>/* global d3, assert, chai, D3Funnel */

describe('D3Funnel', function () {
	var getFunnel, getSvg, getBasicData, getPathHeight, getCommandHeight;

	beforeEach(function (done) {
		getFunnel = function () {
			return new D3Funnel('#funnel');
		};
		getSvg = function () {
			return d3.select('#funnel').selectAll('svg');
		};
		getBasicData = function () {
			return [['Node', 1000]];
		};
		getPathHeight = function (path) {
			var commands = path.attr('d').split(' ');

			return getCommandHeight(commands[2]) - getCommandHeight(commands[0]);
		};
		getCommandHeight = function (command) {
			return parseFloat(command.split(',')[1]);
		};

		done();
	});

	describe('constructor', function () {
		it('should instantiate without error', function () {
			new D3Funnel('#funnel');
		});
	});

	describe('methods', function () {
		describe('draw', function () {
			it('should draw a chart on the identified target', function () {
				getFunnel().draw(getBasicData(), {});

				assert.equal(1, getSvg()[0].length);
			});

			it('should draw when second argument is missing', function () {
				getFunnel().draw(getBasicData());

				assert.equal(1, getSvg()[0].length);
			});

			it('should throw an exception on invalid data', function () {
				var funnel = getFunnel();

				assert.throws(function () {
					funnel.draw(['One dimensional', 2], {});
				}, Error, 'Funnel data is not valid.');
			});

			it('should draw as many blocks as there are elements', function () {
				getFunnel().draw([
					['Node A', 1],
					['Node B', 2],
					['Node C', 3],
					['Node D', 4],
				]);

				assert.equal(4, getSvg().selectAll('path')[0].length);
			});

			it('should use colors assigned to a data element', function () {
				var paths;
				var colorScale;

				getFunnel().draw([
					['A', 1, '#111'],
					['B', 2, '#222'],
					['C', 3],
					['D', 4, '#444'],
				]);

				paths = getSvg().selectAll('path')[0];

				colorScale = d3.scale.category10();

				assert.equal('#111', d3.select(paths[0]).attr('fill'));
				assert.equal('#222', d3.select(paths[1]).attr('fill'));
				assert.equal(colorScale(2), d3.select(paths[2]).attr('fill'));
				assert.equal('#444', d3.select(paths[3]).attr('fill'));
			});

			it('should use label colors assigned to a data element', function () {
				var texts;

				getFunnel().draw([
					['A', 1, null, '#111'],
					['B', 2, null, '#222'],
					['C', 3],
					['D', 4, null, '#444'],
				]);

				texts = getSvg().selectAll('text')[0];

				assert.equal('#111', d3.select(texts[0]).attr('fill'));
				assert.equal('#222', d3.select(texts[1]).attr('fill'));
				assert.equal('#fff', d3.select(texts[2]).attr('fill'));
				assert.equal('#444', d3.select(texts[3]).attr('fill'));
			});
		});

		describe('destroy', function () {
			it('should remove a drawn SVG element', function () {
				var funnel = getFunnel();

				funnel.draw(getBasicData(), {});
				funnel.destroy();

				assert.equal(0, getSvg()[0].length);
			});
		});
	});

	describe('options', function () {
		describe('chart.width', function () {
			it('should set the funnel\'s width to the specified amount', function () {
				getFunnel().draw(getBasicData(), {
					chart: {
						width: 200,
					},
				});

				assert.equal(200, getSvg().node().getBBox().width);
			});
		});

		describe('chart.height', function () {
			it('should set the funnel\'s height to the specified amount', function () {
				getFunnel().draw(getBasicData(), {
					chart: {
						height: 200,
					},
				});

				assert.equal(200, getSvg().node().getBBox().height);
			});
		});

		describe('chart.curve.enabled', function () {
			it('should create an additional path on top of the trapezoids', function () {
				getFunnel().draw(getBasicData(), {
					chart: {
						curve: {
							enabled: true,
						},
					},
				});

				assert.equal(2, d3.selectAll('#funnel path')[0].length);
			});

			it('should create a quadratic Bezier curve on each path', function () {
				getFunnel().draw(getBasicData(), {
					chart: {
						curve: {
							enabled: true,
						},
					},
				});

				var paths = d3.selectAll('#funnel path');

				var quadraticPaths = paths.filter(function () {
					return d3.select(this).attr('d').indexOf('Q') > -1;
				});

				assert.equal(paths[0].length, quadraticPaths[0].length);
			});
		});

		describe('block.dynamicHeight', function () {
			it('should use equal heights when false', function () {
				var paths;

				getFunnel().draw([
					['A', 1],
					['B', 2],
				], {
					chart: {
						height: 300,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.equal(150, getPathHeight(d3.select(paths[0])));
				assert.equal(150, getPathHeight(d3.select(paths[1])));
			});

			it('should use proportional heights when true', function () {
				var paths;

				getFunnel().draw([
					['A', 1],
					['B', 2],
				], {
					chart: {
						height: 300,
					},
					block: {
						dynamicHeight: true,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.equal(100, parseInt(getPathHeight(d3.select(paths[0])), 10));
				assert.equal(200, parseInt(getPathHeight(d3.select(paths[1])), 10));
			});

			it('should not have NaN in the last path when bottomWidth is equal to 0%', function () {
				var paths;

				// A very specific cooked-up example that could trigger NaN
				getFunnel().draw([
					['A', 120],
					['B', 40],
					['C', 20],
					['D', 15],
				], {
					chart: {
						height: 300,
						bottomWidth: 0,
					},
					block: {
						dynamicHeight: true,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.equal(-1, d3.select(paths[3]).attr('d').indexOf('NaN'))
			});

			it('should not error when bottomWidth is equal to 100%', function () {
				var paths;

				getFunnel().draw([
					['A', 1],
					['B', 2],
				], {
					chart: {
						height: 300,
						bottomWidth: 1,
					},
					block: {
						dynamicHeight: true,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

			});
		});

		describe('block.fill.type', function () {
			it('should create gradients when set to \'gradient\'', function () {
				getFunnel().draw(getBasicData(), {
					block: {
						fill: {
							type: 'gradient',
						},
					},
				});

				// Cannot try to re-select the camelCased linearGradient element
				// due to a Webkit bug in the current PhantomJS; workaround is
				// to select the known ID of the linearGradient element
				// https://bugs.webkit.org/show_bug.cgi?id=83438
				assert.equal(1, d3.selectAll('#funnel defs #gradient-0')[0].length);

				assert.equal('url(#gradient-0)', d3.select('#funnel path').attr('fill'));
			});

			it('should use solid fill when not set to \'gradient\'', function () {
				getFunnel().draw(getBasicData(), {});

				// Check for valid hex string
				assert.isTrue(/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(
					d3.select('#funnel path').attr('fill')
				));
			});
		});

		describe('block.minHeight', function () {
			it('should give each block the minimum height specified', function () {
				var paths;

				getFunnel().draw([
					['A', 299],
					['B', 1],
				], {
					chart: {
						height: 300,
					},
					block: {
						dynamicHeight: true,
						minHeight: 10,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.isAbove(parseFloat(getPathHeight(d3.select(paths[0]))), 10);
				assert.isAbove(parseFloat(getPathHeight(d3.select(paths[1]))), 10);
			});

			it('should decrease the height of blocks above the minimum', function () {
				var paths;

				getFunnel().draw([
					['A', 299],
					['B', 1],
				], {
					chart: {
						height: 300,
					},
					block: {
						dynamicHeight: true,
						minHeight: 10,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.isBelow(parseFloat(getPathHeight(d3.select(paths[0]))), 290);
			});
		});

		describe('block.highlight', function () {
			it('should change block color on hover', function () {
				var event = document.createEvent('CustomEvent');
				event.initCustomEvent('mouseover', false, false, null);

				getFunnel().draw([
					['A', 1, '#fff'],
				], {
					block: {
						highlight: true,
					},
				});

				d3.select('#funnel path').node().dispatchEvent(event);

				// #fff * -1/5 => #cccccc
				assert.equal('#cccccc', d3.select('#funnel path').attr('fill'));
			});
		});

		describe('label.fontSize', function () {
			it('should set the label\'s font size to the specified amount', function () {
				getFunnel().draw(getBasicData(), {
					label: {
						fontSize: '16px',
					},
				});

				assert.isTrue(d3.select('#funnel text').attr('style').indexOf('font-size: 16px') > -1);
			});
		});

		describe('label.fill', function () {
			it('should set the label\'s fill color to the specified color', function () {
				getFunnel().draw(getBasicData(), {
					label: {
						fill: '#777',
					},
				});

				assert.isTrue(d3.select('#funnel text').attr('fill').indexOf('#777') > -1);
			});
		});

		describe('label.format', function () {
			it('should parse a string template', function () {
				getFunnel().draw(getBasicData(), {
					label: {
						format: '{l} {v} {f}',
					}
				});

				// Node.js does not have localization, so toLocaleString() will
				// leave the value untouched
				// https://github.com/joyent/node/issues/4689
				assert.equal('Node 1000 1000', d3.select('#funnel text').text());
			});

			it('should pass values to a supplied function', function () {
				getFunnel().draw(getBasicData(), {
					label: {
						format: function (label, value, fValue) {
							return label + '/' + value + '/' + fValue;
						}
					}
				});

				assert.equal('Node/1000/null', d3.select('#funnel text').text());
			});
		});

		describe('events.click.block', function () {
			it('should invoke the callback function with the correct data', function () {
				var event = document.createEvent('CustomEvent');
				event.initCustomEvent('click', false, false, null);

				var spy = chai.spy();

				getFunnel().draw(getBasicData(), {
					events: {
						click: {
							block: function (d, i) {
								spy({
									index: d.index,
									label: d.label.raw,
									value: d.value,
								}, i);
							},
						},
					},
				});

				d3.select('#funnel path').node().dispatchEvent(event);

				chai.expect(spy).to.have.been.called.once.with({
					index: 0,
					label: 'Node',
					value: 1000,
				}, 0);
			});
		});
	});
});
<commit_msg>Move help test functions out of beforeEach<commit_after>/* global d3, assert, chai, D3Funnel */

function getFunnel() {
	return new D3Funnel('#funnel');
}

function getSvg() {
	return d3.select('#funnel').selectAll('svg');
}

function getBasicData() {
	return [['Node', 1000]];
}

function getPathHeight(path) {
	var commands = path.attr('d').split(' ');

	return getCommandHeight(commands[2]) - getCommandHeight(commands[0]);
}

function getCommandHeight(command) {
	return parseFloat(command.split(',')[1]);
}

describe('D3Funnel', function () {
	beforeEach(function (done) {
		done();
	});

	describe('constructor', function () {
		it('should instantiate without error', function () {
			new D3Funnel('#funnel');
		});
	});

	describe('methods', function () {
		describe('draw', function () {
			it('should draw a chart on the identified target', function () {
				getFunnel().draw(getBasicData(), {});

				assert.equal(1, getSvg()[0].length);
			});

			it('should draw when second argument is missing', function () {
				getFunnel().draw(getBasicData());

				assert.equal(1, getSvg()[0].length);
			});

			it('should throw an exception on invalid data', function () {
				var funnel = getFunnel();

				assert.throws(function () {
					funnel.draw(['One dimensional', 2], {});
				}, Error, 'Funnel data is not valid.');
			});

			it('should draw as many blocks as there are elements', function () {
				getFunnel().draw([
					['Node A', 1],
					['Node B', 2],
					['Node C', 3],
					['Node D', 4],
				]);

				assert.equal(4, getSvg().selectAll('path')[0].length);
			});

			it('should use colors assigned to a data element', function () {
				var paths;
				var colorScale;

				getFunnel().draw([
					['A', 1, '#111'],
					['B', 2, '#222'],
					['C', 3],
					['D', 4, '#444'],
				]);

				paths = getSvg().selectAll('path')[0];

				colorScale = d3.scale.category10();

				assert.equal('#111', d3.select(paths[0]).attr('fill'));
				assert.equal('#222', d3.select(paths[1]).attr('fill'));
				assert.equal(colorScale(2), d3.select(paths[2]).attr('fill'));
				assert.equal('#444', d3.select(paths[3]).attr('fill'));
			});

			it('should use label colors assigned to a data element', function () {
				var texts;

				getFunnel().draw([
					['A', 1, null, '#111'],
					['B', 2, null, '#222'],
					['C', 3],
					['D', 4, null, '#444'],
				]);

				texts = getSvg().selectAll('text')[0];

				assert.equal('#111', d3.select(texts[0]).attr('fill'));
				assert.equal('#222', d3.select(texts[1]).attr('fill'));
				assert.equal('#fff', d3.select(texts[2]).attr('fill'));
				assert.equal('#444', d3.select(texts[3]).attr('fill'));
			});
		});

		describe('destroy', function () {
			it('should remove a drawn SVG element', function () {
				var funnel = getFunnel();

				funnel.draw(getBasicData(), {});
				funnel.destroy();

				assert.equal(0, getSvg()[0].length);
			});
		});
	});

	describe('options', function () {
		describe('chart.width', function () {
			it('should set the funnel\'s width to the specified amount', function () {
				getFunnel().draw(getBasicData(), {
					chart: {
						width: 200,
					},
				});

				assert.equal(200, getSvg().node().getBBox().width);
			});
		});

		describe('chart.height', function () {
			it('should set the funnel\'s height to the specified amount', function () {
				getFunnel().draw(getBasicData(), {
					chart: {
						height: 200,
					},
				});

				assert.equal(200, getSvg().node().getBBox().height);
			});
		});

		describe('chart.curve.enabled', function () {
			it('should create an additional path on top of the trapezoids', function () {
				getFunnel().draw(getBasicData(), {
					chart: {
						curve: {
							enabled: true,
						},
					},
				});

				assert.equal(2, d3.selectAll('#funnel path')[0].length);
			});

			it('should create a quadratic Bezier curve on each path', function () {
				getFunnel().draw(getBasicData(), {
					chart: {
						curve: {
							enabled: true,
						},
					},
				});

				var paths = d3.selectAll('#funnel path');

				var quadraticPaths = paths.filter(function () {
					return d3.select(this).attr('d').indexOf('Q') > -1;
				});

				assert.equal(paths[0].length, quadraticPaths[0].length);
			});
		});

		describe('block.dynamicHeight', function () {
			it('should use equal heights when false', function () {
				var paths;

				getFunnel().draw([
					['A', 1],
					['B', 2],
				], {
					chart: {
						height: 300,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.equal(150, getPathHeight(d3.select(paths[0])));
				assert.equal(150, getPathHeight(d3.select(paths[1])));
			});

			it('should use proportional heights when true', function () {
				var paths;

				getFunnel().draw([
					['A', 1],
					['B', 2],
				], {
					chart: {
						height: 300,
					},
					block: {
						dynamicHeight: true,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.equal(100, parseInt(getPathHeight(d3.select(paths[0])), 10));
				assert.equal(200, parseInt(getPathHeight(d3.select(paths[1])), 10));
			});

			it('should not have NaN in the last path when bottomWidth is equal to 0%', function () {
				var paths;

				// A very specific cooked-up example that could trigger NaN
				getFunnel().draw([
					['A', 120],
					['B', 40],
					['C', 20],
					['D', 15],
				], {
					chart: {
						height: 300,
						bottomWidth: 0,
					},
					block: {
						dynamicHeight: true,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.equal(-1, d3.select(paths[3]).attr('d').indexOf('NaN'))
			});

			it('should not error when bottomWidth is equal to 100%', function () {
				var paths;

				getFunnel().draw([
					['A', 1],
					['B', 2],
				], {
					chart: {
						height: 300,
						bottomWidth: 1,
					},
					block: {
						dynamicHeight: true,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

			});
		});

		describe('block.fill.type', function () {
			it('should create gradients when set to \'gradient\'', function () {
				getFunnel().draw(getBasicData(), {
					block: {
						fill: {
							type: 'gradient',
						},
					},
				});

				// Cannot try to re-select the camelCased linearGradient element
				// due to a Webkit bug in the current PhantomJS; workaround is
				// to select the known ID of the linearGradient element
				// https://bugs.webkit.org/show_bug.cgi?id=83438
				assert.equal(1, d3.selectAll('#funnel defs #gradient-0')[0].length);

				assert.equal('url(#gradient-0)', d3.select('#funnel path').attr('fill'));
			});

			it('should use solid fill when not set to \'gradient\'', function () {
				getFunnel().draw(getBasicData(), {});

				// Check for valid hex string
				assert.isTrue(/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(
					d3.select('#funnel path').attr('fill')
				));
			});
		});

		describe('block.minHeight', function () {
			it('should give each block the minimum height specified', function () {
				var paths;

				getFunnel().draw([
					['A', 299],
					['B', 1],
				], {
					chart: {
						height: 300,
					},
					block: {
						dynamicHeight: true,
						minHeight: 10,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.isAbove(parseFloat(getPathHeight(d3.select(paths[0]))), 10);
				assert.isAbove(parseFloat(getPathHeight(d3.select(paths[1]))), 10);
			});

			it('should decrease the height of blocks above the minimum', function () {
				var paths;

				getFunnel().draw([
					['A', 299],
					['B', 1],
				], {
					chart: {
						height: 300,
					},
					block: {
						dynamicHeight: true,
						minHeight: 10,
					},
				});

				paths = d3.selectAll('#funnel path')[0];

				assert.isBelow(parseFloat(getPathHeight(d3.select(paths[0]))), 290);
			});
		});

		describe('block.highlight', function () {
			it('should change block color on hover', function () {
				var event = document.createEvent('CustomEvent');
				event.initCustomEvent('mouseover', false, false, null);

				getFunnel().draw([
					['A', 1, '#fff'],
				], {
					block: {
						highlight: true,
					},
				});

				d3.select('#funnel path').node().dispatchEvent(event);

				// #fff * -1/5 => #cccccc
				assert.equal('#cccccc', d3.select('#funnel path').attr('fill'));
			});
		});

		describe('label.fontSize', function () {
			it('should set the label\'s font size to the specified amount', function () {
				getFunnel().draw(getBasicData(), {
					label: {
						fontSize: '16px',
					},
				});

				assert.isTrue(d3.select('#funnel text').attr('style').indexOf('font-size: 16px') > -1);
			});
		});

		describe('label.fill', function () {
			it('should set the label\'s fill color to the specified color', function () {
				getFunnel().draw(getBasicData(), {
					label: {
						fill: '#777',
					},
				});

				assert.isTrue(d3.select('#funnel text').attr('fill').indexOf('#777') > -1);
			});
		});

		describe('label.format', function () {
			it('should parse a string template', function () {
				getFunnel().draw(getBasicData(), {
					label: {
						format: '{l} {v} {f}',
					}
				});

				// Node.js does not have localization, so toLocaleString() will
				// leave the value untouched
				// https://github.com/joyent/node/issues/4689
				assert.equal('Node 1000 1000', d3.select('#funnel text').text());
			});

			it('should pass values to a supplied function', function () {
				getFunnel().draw(getBasicData(), {
					label: {
						format: function (label, value, fValue) {
							return label + '/' + value + '/' + fValue;
						}
					}
				});

				assert.equal('Node/1000/null', d3.select('#funnel text').text());
			});
		});

		describe('events.click.block', function () {
			it('should invoke the callback function with the correct data', function () {
				var event = document.createEvent('CustomEvent');
				event.initCustomEvent('click', false, false, null);

				var spy = chai.spy();

				getFunnel().draw(getBasicData(), {
					events: {
						click: {
							block: function (d, i) {
								spy({
									index: d.index,
									label: d.label.raw,
									value: d.value,
								}, i);
							},
						},
					},
				});

				d3.select('#funnel path').node().dispatchEvent(event);

				chai.expect(spy).to.have.been.called.once.with({
					index: 0,
					label: 'Node',
					value: 1000,
				}, 0);
			});
		});
	});
});
<|endoftext|>


<commit_before>var _ = require('lodash');

module.exports = (function () { // eslint-disable-line no-unused-vars
  function requireArgument (value, message) {
    if (_.isUndefined(value)) { throw new Error(message); }
  }

  function stripTrailingSlash (string) {
    return string.replace(/\/?$/, '');
  }

  function stripBeginingSlash (string) {
    return string.replace(/^\/?/, '');
  }

  function stripEndSlashes (string) {
    return stripTrailingSlash(stripBeginingSlash(string));
  }

  function SpecialCoverageLoader (element, listElement, options) {
    requireArgument(element, 'new SpecialCoverageLoader(element, listElement, options): element is undefined');
    requireArgument(listElement, 'new SpecialCoverageLoader(element, listElement, options): listElement is undefined');
    requireArgument(element.dataset.total, 'new SpecialCoverageLoader(element, listElement, options): element has no data-total value');
    requireArgument(element.dataset.perPage, 'new SpecialCoverageLoader(element, listElement, options): element has no data-per-page value');

    options = options || {};
    this.total = parseInt(element.dataset.total, 10);
    this.perPage = parseInt(element.dataset.perPage, 10);
    this.currentPage = 1;
    this.listElement = listElement;
    this.element = element;
    this.isLoading = false;
    this.defaultText = element.innerHTML;
    this.loadingText = 'Loading...';

    var defaultBaseUrl = [
      window.location.protocol, '//',
      window.location.hostname + ':' + window.location.port,
      window.location.pathname,
      window.location.search,
      window.location.hash,
    ].join('');

    _.defaults(options, { baseUrl: defaultBaseUrl });
    options.baseUrl = stripTrailingSlash(options.baseUrl);
    _.assign(this, options);

    element.addEventListener('click', function () {
      var url = this.buildUrl(this.currentPage, this.perPage, this.baseUrl);
      this.loadMore(url);
    }.bind(this));
  }

  _.assign(SpecialCoverageLoader.prototype, {
    nextOffset: function (currentPage, perPage) {
      requireArgument(currentPage, 'SpecialCoverageLoader.nextOffset(currentPage, perPage): currentPage is undefined');
      requireArgument(perPage, 'SpecialCoverageLoader.nextOffset(currentPage, perPage): perPage is undefined');

      return currentPage * perPage;
    },

    buildUrl: function (currentPage, perPage, baseUrl) {
      requireArgument(currentPage, 'SpecialCoverageLoader.buildUrl(currentPage, perPage, baseUrl, offset): currentPage is undefined');
      requireArgument(perPage, 'SpecialCoverageLoader.buildUrl(currentPage, perPage, baseUrl, offset): perPage is undefined');
      requireArgument(baseUrl, 'SpecialCoverageLoader.buildUrl(currentPage, perPage, baseUrl, offset): baseUrl is undefined');

      var offset = this.nextOffset(currentPage, perPage);
      var parser = document.createElement('a');

      parser.href = stripTrailingSlash(baseUrl);

      return _.compact([
        parser.protocol + '/',
        parser.hostname,
        stripEndSlashes(parser.pathname),
        'more',
        offset + parser.search,
      ]).join('/');
    },

    loadMore: function (url) {
      if (this.isLoading) { return; }
      requireArgument(url, 'SpecialCoverageLoader.loadMore(url): url is undefined');
      this.isLoading = true;
      this.element.innerHTML = this.loadingText;
      $.ajax({
        url: url,
        type: 'get',
        dataType: 'html',
      })
        .done(this.handleLoadMoreSuccess.bind(this))
        .fail(this.handleLoadMoreFailure.bind(this));
    },

    toggleLoadingState: function (loadingState, element) {
      requireArgument(loadingState, 'SpecialCoverageLoader.toggleLoadingState(loadingState, element): loadingState is undefined');
      requireArgument(element, 'SpecialCoverageLoader.toggleLoadingState(loadingState, element): element is undefined');
      this.isLoading = !loadingState;
      element.innerHTML = this.isLoading ? this.loadingText : this.defaultText;
    },

    handleLoadMoreSuccess: function (response) {
      this.toggleLoadingState(this.isLoading, this.element);
      requireArgument(response, 'SpecialCoverageLoader.handleLoadMoreSuccess(response): response is undefined');
      response = response.trim();
      if (response) {
        this.currentPage += 1;
        this.listElement.innerHTML = this.listElement.innerHTML + response;
      }
      this.setButtonVisibility(response);
    },

    handleLoadMoreFailure: function (response) {
      this.toggleLoadingState(this.isLoading, this.element);
      requireArgument(response, 'SpecialCoverageLoader.handleLoadMoreFailure(response): response id undefined');

      var message = [
        'SpecialCoverageLoader.loadMore("',
        this.buildUrl(this.currentPage, this.perPage, this.baseUrl),
        '"): server responded with "',
        response.status,
        ' ',
        response.statusText,
        '"',
      ].join('');

      console.log(message);
    },

    hideElement: function () {
      this.element.style.display = 'none';
    },

    isLastPage: function (total, listElement) {
      requireArgument(total, 'SpecialCoverageLoader.isLastPage(total, listElement): total is undefined');
      requireArgument(listElement, 'SpecialCoverageLoader.isLastPage(total, listElement): listElement is undefined');

      var listItems = [];
      for (var i = 0; i < listElement.children.length; i += 1) {
        var item = listElement.children[i];

        if (item.classList.contains('sc-landing-list-item')) {
          listItems.push(item);
        }
      }

      return total <= listItems.length;
    },

    setButtonVisibility: function (response) {
      requireArgument(response, 'SpecialCoverageLoader.setButtonVisibility(response): response is undefined');

      if (!response || this.isLastPage(this.total, this.listElement)) {
        this.hideElement();
      }
    },
  });
  return SpecialCoverageLoader;
})();
<commit_msg>Remove dependency on lodash again<commit_after>module.exports = (function () { // eslint-disable-line no-unused-vars
  // These quasi-copies of lodash methods are used instead of lodash
  // because we do not want to depend on it here
  function isUndefined (suspect) {
    return typeof(suspect) === 'undefined';
  }

  function requireArgument (value, message) {
    if (isUndefined(value)) { throw new Error(message); }
  }

  function assign (target, source) {
    Object.keys(source).forEach(function (key) {
      target[key] = source[key];
    });
  }

  function defaults (target, source) {
    Object.keys(source).forEach(function (key) {
      if (!target[key]) { target[key] = source[key]; }
    });
  }

  function stripTrailingSlash (string) {
    return string.replace(/\/?$/, '');
  }

  function stripBeginingSlash (string) {
    return string.replace(/^\/?/, '');
  }

  function stripEndSlashes (string) {
    return stripTrailingSlash(stripBeginingSlash(string));
  }

  function compact (list) {
    var newList = [];
    list.forEach(function (item) {
      if (!isUndefined(item) || item.length > 0) {
        newList.push(item);
      }
    });

    return newList;
  }

  function SpecialCoverageLoader (element, listElement, options) {
    requireArgument(element, 'new SpecialCoverageLoader(element, listElement, options): element is undefined');
    requireArgument(listElement, 'new SpecialCoverageLoader(element, listElement, options): listElement is undefined');
    requireArgument(element.dataset.total, 'new SpecialCoverageLoader(element, listElement, options): element has no data-total value');
    requireArgument(element.dataset.perPage, 'new SpecialCoverageLoader(element, listElement, options): element has no data-per-page value');

    options = options || {};
    this.total = parseInt(element.dataset.total, 10);
    this.perPage = parseInt(element.dataset.perPage, 10);
    this.currentPage = 1;
    this.listElement = listElement;
    this.element = element;
    this.isLoading = false;
    this.defaultText = element.innerHTML;
    this.loadingText = 'Loading...';

    var defaultBaseUrl = [
      window.location.protocol, '//',
      window.location.hostname + ':' + window.location.port,
      window.location.pathname,
      window.location.search,
      window.location.hash,
    ].join('');

    defaults(options, { baseUrl: defaultBaseUrl });
    options.baseUrl = stripTrailingSlash(options.baseUrl);
    assign(this, options);

    element.addEventListener('click', function () {
      var url = this.buildUrl(this.currentPage, this.perPage, this.baseUrl);
      this.loadMore(url);
    }.bind(this));
  }

  assign(SpecialCoverageLoader.prototype, {
    nextOffset: function (currentPage, perPage) {
      requireArgument(currentPage, 'SpecialCoverageLoader.nextOffset(currentPage, perPage): currentPage is undefined');
      requireArgument(perPage, 'SpecialCoverageLoader.nextOffset(currentPage, perPage): perPage is undefined');

      return currentPage * perPage;
    },

    buildUrl: function (currentPage, perPage, baseUrl) {
      requireArgument(currentPage, 'SpecialCoverageLoader.buildUrl(currentPage, perPage, baseUrl, offset): currentPage is undefined');
      requireArgument(perPage, 'SpecialCoverageLoader.buildUrl(currentPage, perPage, baseUrl, offset): perPage is undefined');
      requireArgument(baseUrl, 'SpecialCoverageLoader.buildUrl(currentPage, perPage, baseUrl, offset): baseUrl is undefined');

      var offset = this.nextOffset(currentPage, perPage);
      var parser = document.createElement('a');

      parser.href = stripTrailingSlash(baseUrl);

      return compact([
        parser.protocol + '/',
        parser.hostname,
        stripEndSlashes(parser.pathname),
        'more',
        offset + parser.search,
      ]).join('/');
    },

    loadMore: function (url) {
      if (this.isLoading) { return; }
      requireArgument(url, 'SpecialCoverageLoader.loadMore(url): url is undefined');
      this.isLoading = true;
      this.element.innerHTML = this.loadingText;
      $.ajax({
        url: url,
        type: 'get',
        dataType: 'html',
      })
        .done(this.handleLoadMoreSuccess.bind(this))
        .fail(this.handleLoadMoreFailure.bind(this));
    },

    toggleLoadingState: function (loadingState, element) {
      requireArgument(loadingState, 'SpecialCoverageLoader.toggleLoadingState(loadingState, element): loadingState is undefined');
      requireArgument(element, 'SpecialCoverageLoader.toggleLoadingState(loadingState, element): element is undefined');
      this.isLoading = !loadingState;
      element.innerHTML = this.isLoading ? this.loadingText : this.defaultText;
    },

    handleLoadMoreSuccess: function (response) {
      this.toggleLoadingState(this.isLoading, this.element);
      requireArgument(response, 'SpecialCoverageLoader.handleLoadMoreSuccess(response): response is undefined');
      response = response.trim();
      if (response) {
        this.currentPage += 1;
        this.listElement.innerHTML = this.listElement.innerHTML + response;
      }
      this.setButtonVisibility(response);
    },

    handleLoadMoreFailure: function (response) {
      this.toggleLoadingState(this.isLoading, this.element);
      requireArgument(response, 'SpecialCoverageLoader.handleLoadMoreFailure(response): response id undefined');

      var message = [
        'SpecialCoverageLoader.loadMore("',
        this.buildUrl(this.currentPage, this.perPage, this.baseUrl),
        '"): server responded with "',
        response.status,
        ' ',
        response.statusText,
        '"',
      ].join('');

      console.log(message);
    },

    hideElement: function () {
      this.element.style.display = 'none';
    },

    isLastPage: function (total, listElement) {
      requireArgument(total, 'SpecialCoverageLoader.isLastPage(total, listElement): total is undefined');
      requireArgument(listElement, 'SpecialCoverageLoader.isLastPage(total, listElement): listElement is undefined');

      var listItems = [];
      for (var i = 0; i < listElement.children.length; i += 1) {
        var item = listElement.children[i];

        if (item.classList.contains('sc-landing-list-item')) {
          listItems.push(item);
        }
      }

      return total <= listItems.length;
    },

    setButtonVisibility: function (response) {
      requireArgument(response, 'SpecialCoverageLoader.setButtonVisibility(response): response is undefined');

      if (!response || this.isLastPage(this.total, this.listElement)) {
        this.hideElement();
      }
    },
  });
  return SpecialCoverageLoader;
})();
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 ONOS GUI -- Topology Link Module.
 Functions for highlighting/selecting links
 */

(function () {
    'use strict';

    // injected refs
    var $log, fs, sus, ts;

    var api,
        td3,
        network,
        enhancedLink = null;    // the link which the mouse is hovering over

    // SVG elements;
    var svg, mouseG;

    // ======== ALGORITHM TO FIND LINK CLOSEST TO MOUSE ========

    function setupMouse(forceG, zoomer) {
        $log.debug('set up mouse handlers for mouse move');
        mouseG = forceG.append('g').attr('id', 'topo-mouse');
        //mouseG.append('circle')
        //    .attr({
        //        r: 5,
        //        opacity: 0
        //    })
        //    .style('fill', 'red');

        svg.on('mouseenter', function () {
            //$log.log('M--ENTER');
            //mouseG.selectAll('circle').attr('opacity', 1);
        })
            .on('mouseleave', function () {
                //$log.log('M--LEAVE');
                //mouseG.selectAll('circle').attr('opacity', 0);
            })
            .on('mousemove', function () {
                var m = d3.mouse(this),
                    sc = zoomer.scale(),
                    tr = zoomer.translate(),
                    mx = (m[0] - tr[0]) / sc,
                    my = (m[1] - tr[1]) / sc;

                //$log.log('M--MOVE', m);

                //mouseG.selectAll('circle')
                //    .attr({
                //        cx: mx,
                //        cy: my
                //    });
                updatePerps({x: mx, y: my}, zoomer);
            });
    }

    function updatePerps(mouse, zoomer) {
        var proximity = 30 / zoomer.scale(),
            perpData, perps, nearest, minDist;

        function sq(x) { return x * x; }

        function pdrop(line, mouse) {
            var x1 = line.x1,
                y1 = line.y1,
                x2 = line.x2,
                y2 = line.y2,
                x3 = mouse.x,
                y3 = mouse.y,
                k = ((y2-y1) * (x3-x1) - (x2-x1) * (y3-y1)) /
                    (sq(y2-y1) + sq(x2-x1)),
                x4 = x3 - k * (y2-y1),
                y4 = y3 + k * (x2-x1);
            return {x:x4, y:y4};
        }

        function mdist(p, m) {
            return Math.sqrt(sq(p.x - m.x) + sq(p.y - m.y));
        }

        function lineSeg(d) {
            return {
                x1: d.source.x,
                y1: d.source.y,
                x2: d.target.x,
                y2: d.target.y
            };
        }

        function lineHit(line, p, m) {
            if (p.x < line.x1 && p.x < line.x2) return false;
            if (p.x > line.x1 && p.x > line.x2) return false;
            if (p.y < line.y1 && p.y < line.y2) return false;
            if (p.y > line.y1 && p.y > line.y2) return false;
            // line intersects, but are we close enough?
            return mdist(p, m) <= proximity;
        }

        if (network.links.length) {
            perpData = [];
            nearest = null;
            minDist = proximity * 2;

            network.links.forEach(function (d) {
                if (!api.showHosts() && d.type() === 'hostLink') {
                    return; // skip hidden host links
                }

                var line = lineSeg(d),
                    point = pdrop(line, mouse),
                    hit = lineHit(line, point, mouse),
                    dist;

                if (hit) {
                    dist = mdist(point, mouse);
                    if (dist < minDist) {
                        minDist = dist;
                        nearest = d;
                    }
                    /*
                     perpData.push({
                     key: d.key,
                     x1: mouse.x,
                     y1: mouse.y,
                     x2: point.x,
                     y2: point.y
                     });
                     */
                }
            });

            /*
             perps = mouseG.selectAll('line')
             .data(perpData, function (d) { return d.key; })
             .attr({
             x1: function (d) { return d.x1; },
             y1: function (d) { return d.y1; },
             x2: function (d) { return d.x2; },
             y2: function (d) { return d.y2; }
             });

             perps.enter().append('line')
             .attr({
             x1: function (d) { return d.x1; },
             y1: function (d) { return d.y1; },
             x2: function (d) { return d.x2; },
             y2: function (d) { return d.y2; }
             })
             .style('stroke-width', 2)
             .style('stroke', 'limegreen');

             perps.exit().remove();
             */

            enhanceNearestLink(nearest);
        }
    }

    function enhanceNearestLink(ldata) {
        // if the new link is same as old link, do nothing
        if (enhancedLink && ldata && enhancedLink.key === ldata.key) return;

        // first, unenhance the currently enhanced link
        if (enhancedLink) {
            unenhance(enhancedLink);
        }
        enhancedLink = ldata;
        if (enhancedLink) {
            enhance(enhancedLink);
        }
    }

    function unenhance(d) {
        d.el.classed('enhanced', false);
        api.portLabelG().selectAll('.portLabel').remove();
    }

    function enhance(d) {
        d.el.classed('enhanced', true);
        $log.debug('[' + (d.srcPort || 'H') + '] ---> [' + d.tgtPort + ']', d.key);

        // define port label data objects
        var data = [
            {
                id: 'topo-port-src',
                num: d.srcPort,
                baseX: d.source.x,
                baseY: d.source.y
            },
            {
                id: 'topo-port-tgt',
                num: d.tgtPort,
                baseX: d.target.x,
                baseY: d.target.y
            }
        ];

        td3.applyPortLabels(data, api.portLabelG());
    }

    // ==========================
    // Module definition

    angular.module('ovTopo')
        .factory('TopoLinkService',
        ['$log', 'FnService', 'SvgUtilService', 'ThemeService',

            function (_$log_, _fs_, _sus_, _ts_) {
                $log = _$log_;
                fs = _fs_;
                sus = _sus_;
                ts = _ts_;

                function initLink(_api_, _td3_) {
                    api = _api_;
                    td3 = _td3_;
                    svg = api.svg;
                    network = api.network;
                    setupMouse(api.forceG, api.zoomer);
                }

                function destroyLink() {
                    svg.on('mouseenter', null)
                        .on('mouseleave', null)
                        .on('mousemove', null);
                }

                return {
                    initLink: initLink,
                    destroyLink: destroyLink
                };
            }]);
}());
<commit_msg>GUI -- TopoView - don't add source port on host link.<commit_after>/*
 * Copyright 2015 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 ONOS GUI -- Topology Link Module.
 Functions for highlighting/selecting links
 */

(function () {
    'use strict';

    // injected refs
    var $log, fs, sus, ts;

    var api,
        td3,
        network,
        enhancedLink = null;    // the link which the mouse is hovering over

    // SVG elements;
    var svg, mouseG;

    // ======== ALGORITHM TO FIND LINK CLOSEST TO MOUSE ========

    function setupMouse(forceG, zoomer) {
        $log.debug('set up mouse handlers for mouse move');
        mouseG = forceG.append('g').attr('id', 'topo-mouse');
        //mouseG.append('circle')
        //    .attr({
        //        r: 5,
        //        opacity: 0
        //    })
        //    .style('fill', 'red');

        svg.on('mouseenter', function () {
            //$log.log('M--ENTER');
            //mouseG.selectAll('circle').attr('opacity', 1);
        })
            .on('mouseleave', function () {
                //$log.log('M--LEAVE');
                //mouseG.selectAll('circle').attr('opacity', 0);
            })
            .on('mousemove', function () {
                var m = d3.mouse(this),
                    sc = zoomer.scale(),
                    tr = zoomer.translate(),
                    mx = (m[0] - tr[0]) / sc,
                    my = (m[1] - tr[1]) / sc;

                //$log.log('M--MOVE', m);

                //mouseG.selectAll('circle')
                //    .attr({
                //        cx: mx,
                //        cy: my
                //    });
                updatePerps({x: mx, y: my}, zoomer);
            });
    }

    function updatePerps(mouse, zoomer) {
        var proximity = 30 / zoomer.scale(),
            perpData, perps, nearest, minDist;

        function sq(x) { return x * x; }

        function pdrop(line, mouse) {
            var x1 = line.x1,
                y1 = line.y1,
                x2 = line.x2,
                y2 = line.y2,
                x3 = mouse.x,
                y3 = mouse.y,
                k = ((y2-y1) * (x3-x1) - (x2-x1) * (y3-y1)) /
                    (sq(y2-y1) + sq(x2-x1)),
                x4 = x3 - k * (y2-y1),
                y4 = y3 + k * (x2-x1);
            return {x:x4, y:y4};
        }

        function mdist(p, m) {
            return Math.sqrt(sq(p.x - m.x) + sq(p.y - m.y));
        }

        function lineSeg(d) {
            return {
                x1: d.source.x,
                y1: d.source.y,
                x2: d.target.x,
                y2: d.target.y
            };
        }

        function lineHit(line, p, m) {
            if (p.x < line.x1 && p.x < line.x2) return false;
            if (p.x > line.x1 && p.x > line.x2) return false;
            if (p.y < line.y1 && p.y < line.y2) return false;
            if (p.y > line.y1 && p.y > line.y2) return false;
            // line intersects, but are we close enough?
            return mdist(p, m) <= proximity;
        }

        if (network.links.length) {
            perpData = [];
            nearest = null;
            minDist = proximity * 2;

            network.links.forEach(function (d) {
                if (!api.showHosts() && d.type() === 'hostLink') {
                    return; // skip hidden host links
                }

                var line = lineSeg(d),
                    point = pdrop(line, mouse),
                    hit = lineHit(line, point, mouse),
                    dist;

                if (hit) {
                    dist = mdist(point, mouse);
                    if (dist < minDist) {
                        minDist = dist;
                        nearest = d;
                    }
                    /*
                     perpData.push({
                     key: d.key,
                     x1: mouse.x,
                     y1: mouse.y,
                     x2: point.x,
                     y2: point.y
                     });
                     */
                }
            });

            /*
             perps = mouseG.selectAll('line')
             .data(perpData, function (d) { return d.key; })
             .attr({
             x1: function (d) { return d.x1; },
             y1: function (d) { return d.y1; },
             x2: function (d) { return d.x2; },
             y2: function (d) { return d.y2; }
             });

             perps.enter().append('line')
             .attr({
             x1: function (d) { return d.x1; },
             y1: function (d) { return d.y1; },
             x2: function (d) { return d.x2; },
             y2: function (d) { return d.y2; }
             })
             .style('stroke-width', 2)
             .style('stroke', 'limegreen');

             perps.exit().remove();
             */

            enhanceNearestLink(nearest);
        }
    }

    function enhanceNearestLink(ldata) {
        // if the new link is same as old link, do nothing
        if (enhancedLink && ldata && enhancedLink.key === ldata.key) return;

        // first, unenhance the currently enhanced link
        if (enhancedLink) {
            unenhance(enhancedLink);
        }
        enhancedLink = ldata;
        if (enhancedLink) {
            enhance(enhancedLink);
        }
    }

    function unenhance(d) {
        d.el.classed('enhanced', false);
        api.portLabelG().selectAll('.portLabel').remove();
    }

    function enhance(d) {
        d.el.classed('enhanced', true);
        $log.debug('[' + (d.srcPort || 'H') + '] ---> [' + d.tgtPort + ']', d.key);

        // Define port label data objects.
        // NOTE: src port is absent in the case of host-links.

        var data = [{
            id: 'topo-port-tgt',
            num: d.tgtPort,
            baseX: d.target.x,
            baseY: d.target.y
        }];

        if (d.srcPort) {
            data.push({
                id: 'topo-port-src',
                num: d.srcPort,
                baseX: d.source.x,
                baseY: d.source.y
            });
        }

        td3.applyPortLabels(data, api.portLabelG());
    }

    // ==========================
    // Module definition

    angular.module('ovTopo')
        .factory('TopoLinkService',
        ['$log', 'FnService', 'SvgUtilService', 'ThemeService',

            function (_$log_, _fs_, _sus_, _ts_) {
                $log = _$log_;
                fs = _fs_;
                sus = _sus_;
                ts = _ts_;

                function initLink(_api_, _td3_) {
                    api = _api_;
                    td3 = _td3_;
                    svg = api.svg;
                    network = api.network;
                    setupMouse(api.forceG, api.zoomer);
                }

                function destroyLink() {
                    svg.on('mouseenter', null)
                        .on('mouseleave', null)
                        .on('mousemove', null);
                }

                return {
                    initLink: initLink,
                    destroyLink: destroyLink
                };
            }]);
}());
<|endoftext|>


<commit_before>ManageIQ.angular.app.service('topologyService', function() {

  this.tooltip = function tooltip(d) {
    var status = [
      __("Name: ") + d.item.name,
      __("Type: ") + d.item.display_kind,
      __("Status: ") + d.item.status
    ];

    if (d.item.kind == 'Host' || d.item.kind == 'Vm') {
      status.push(__("Provider: ") + d.item.provider);
    }

    return status;
  };

  this.addContextMenuOption = function(popup, text, data, callback) {
    popup.append("p").text(text)
      .on('click' , function() {callback(data);});
  };

  this.searchNode = function(svg, query) {
    var nodes = svg.selectAll("g");
    if (query != "") {
      var selected = nodes.filter(function (d) {
        return d.item.name != query;
      });
      selected.style("opacity", "0.2");
      var links = svg.selectAll("line");
      links.style("opacity", "0.2");
    }
  };

  this.resetSearch = function(d3) {
    // Display all topology nodes and links
    d3.selectAll("g, line").transition()
      .duration(2000)
      .style("opacity", 1);
  };

  this.geturl = function(d) {
    var entity_url = "";
    var action = '/show/' + d.item.miq_id;
    switch (d.item.kind) {
      case "ContainerManager":
        entity_url = "ems_container";
        break;
      case "NetworkManager":
        entity_url = "ems_network";
        break;
      case "MiddlewareManager":
        entity_url = "ems_middleware";
        break;
      default :
        entity_url = _.snakeCase(d.item.kind);
      }

      return '/' + entity_url + action;
  };

  this.getSVG = function(d3) {
    var graph = d3.select("kubernetes-topology-graph");
    var svg = graph.select('svg');
    return svg;
  };

  this.defaultElementDimensions = function() {
    return { x: 0, y: 9, r: 17 };
  };

  this.getItemStatusClass = function(d) {
    switch (d.item.status) {
      case "OK":
      case "Active":
      case "Available":
      case "On":
      case "Ready":
      case "Running":
      case "Succeeded":
      case "Valid":
        return "success";
      case "NotReady":
      case "Failed":
      case "Error":
      case "Unreachable":
        return "error";
      case 'Warning':
      case 'Waiting':
      case 'Pending':
        return "warning";
      case 'Unknown':
      case 'Terminated':
        return "unknown";
    }
  };

});
<commit_msg>Add support for substring in topology search Allow search for substrings and not only exact string match in the topology.<commit_after>ManageIQ.angular.app.service('topologyService', function() {

  this.tooltip = function tooltip(d) {
    var status = [
      __("Name: ") + d.item.name,
      __("Type: ") + d.item.display_kind,
      __("Status: ") + d.item.status
    ];

    if (d.item.kind == 'Host' || d.item.kind == 'Vm') {
      status.push(__("Provider: ") + d.item.provider);
    }

    return status;
  };

  this.addContextMenuOption = function(popup, text, data, callback) {
    popup.append("p").text(text)
      .on('click' , function() {callback(data);});
  };

  this.searchNode = function(svg, query) {
    var nodes = svg.selectAll("g");
    if (query != "") {
      var selected = nodes.filter(function (d) {
        return d.item.name.indexOf(query) == -1;
      });
      selected.style("opacity", "0.2");
      var links = svg.selectAll("line");
      links.style("opacity", "0.2");
    }
  };

  this.resetSearch = function(d3) {
    // Display all topology nodes and links
    d3.selectAll("g, line").transition()
      .duration(2000)
      .style("opacity", 1);
  };

  this.geturl = function(d) {
    var entity_url = "";
    var action = '/show/' + d.item.miq_id;
    switch (d.item.kind) {
      case "ContainerManager":
        entity_url = "ems_container";
        break;
      case "NetworkManager":
        entity_url = "ems_network";
        break;
      case "MiddlewareManager":
        entity_url = "ems_middleware";
        break;
      default :
        entity_url = _.snakeCase(d.item.kind);
      }

      return '/' + entity_url + action;
  };

  this.getSVG = function(d3) {
    var graph = d3.select("kubernetes-topology-graph");
    var svg = graph.select('svg');
    return svg;
  };

  this.defaultElementDimensions = function() {
    return { x: 0, y: 9, r: 17 };
  };

  this.getItemStatusClass = function(d) {
    switch (d.item.status) {
      case "OK":
      case "Active":
      case "Available":
      case "On":
      case "Ready":
      case "Running":
      case "Succeeded":
      case "Valid":
        return "success";
      case "NotReady":
      case "Failed":
      case "Error":
      case "Unreachable":
        return "error";
      case 'Warning':
      case 'Waiting':
      case 'Pending':
        return "warning";
      case 'Unknown':
      case 'Terminated':
        return "unknown";
    }
  };

});
<|endoftext|>


<commit_before>Template.settings.rendered=function(){
	$('.button-collapse').sideNav({
      edge: 'left', // Choose the horizontal origin
      closeOnClick: true // Closes side-nav on <a> clicks, useful for Angular/Meteor
    }
  );
}
Template.settings.helpers({
	profilbild:function(){
		return Meteor.user().profile.profilbild;
	},
	username:function(){
		return Meteor.user().username;
	},
	version:function(){
    return Version.findOne();
  }
})
Template.settings.events({
	"click #btn_goto_home1":function(event, template){
		if (Roles.userIsInRole({_id: Meteor.userId()}, "helper")) {
			Router.go("homeHelper")
		} else if (Roles.userIsInRole({_id: Meteor.userId()}, "blind")) {
			Router.go("homeBlind")
		};
	},
	"click #btn_goto_home2":function(event, template){
		if (Roles.userIsInRole({_id: Meteor.userId()}, "helper")) {
			Router.go("homeHelper")
		} else if (Roles.userIsInRole({_id: Meteor.userId()}, "blind")) {
			Router.go("homeBlind")
		};
	},
	"click #btn_logout_about1":function(event, template){
		Router.go("confirmLogout")
	},
	"click #btn_logout_about2":function(event, template){
		Router.go("confirmLogout")
	},
	"click #btn_changeSettings":function(event, template){
		if(document.getElementById("test4").checked){
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "blue")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "red")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "yellow")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "green")
			Roles.addUsersToRoles({_id: Meteor.userId()}, "blue")
		} else if(document.getElementById("test1").checked){
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "blue")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "red")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "yellow")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "green")
			Roles.addUsersToRoles({_id: Meteor.userId()}, "red")
		} else if(document.getElementById("test2").checked){
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "blue")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "red")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "yellow")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "green")
			Roles.addUsersToRoles({_id: Meteor.userId()}, "yellow")
		} else if(document.getElementById("test3").checked){
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "blue")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "red")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "yellow")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "green")
			Roles.addUsersToRoles({_id: Meteor.userId()}, "green")
		}
	}
})
<commit_msg>neues Farbschema zur Auswahl<commit_after>Template.settings.rendered=function(){
	$('.button-collapse').sideNav({
      edge: 'left', // Choose the horizontal origin
      closeOnClick: true // Closes side-nav on <a> clicks, useful for Angular/Meteor
    }
  );
}
Template.settings.helpers({
	profilbild:function(){
		return Meteor.user().profile.profilbild;
	},
	username:function(){
		return Meteor.user().username;
	},
	version:function(){
    return Version.findOne();
  }
})
Template.settings.events({
	"click #btn_goto_home1":function(event, template){
		if (Roles.userIsInRole({_id: Meteor.userId()}, "helper")) {
			Router.go("homeHelper")
		} else if (Roles.userIsInRole({_id: Meteor.userId()}, "blind")) {
			Router.go("homeBlind")
		};
	},
	"click #btn_goto_home2":function(event, template){
		if (Roles.userIsInRole({_id: Meteor.userId()}, "helper")) {
			Router.go("homeHelper")
		} else if (Roles.userIsInRole({_id: Meteor.userId()}, "blind")) {
			Router.go("homeBlind")
		};
	},
	"click #btn_logout_about1":function(event, template){
		Router.go("confirmLogout")
	},
	"click #btn_logout_about2":function(event, template){
		Router.go("confirmLogout")
	},
	"click #btn_changeSettings":function(event, template){
		if(document.getElementById("test4").checked){
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "blue")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "red")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "yellow")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "green")
			Roles.addUsersToRoles({_id: Meteor.userId()}, "blue")
		} else if(document.getElementById("test1").checked){
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "blue")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "red")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "yellow")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "green")
			Roles.addUsersToRoles({_id: Meteor.userId()}, "red")
		} else if(document.getElementById("test2").checked){
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "blue")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "red")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "yellow")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "green")
			Roles.addUsersToRoles({_id: Meteor.userId()}, "yellow")
		} else if(document.getElementById("test3").checked){
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "blue")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "red")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "yellow")
			Roles.removeUsersFromRoles({_id: Meteor.userId()}, "green")
			Roles.addUsersToRoles({_id: Meteor.userId()}, "green")
		};
		if(Roles.userIsInRole({_id: Meteor.userId()}, "blind")){
			Router.go("homeBlind")
		} else if(Roles.userIsInRole({_id: Meteor.userId()}, "helper")){
			Router.go("homeHelper")
		}
	}
})
<|endoftext|>


<commit_before>var pw_sets = new Hash;
pw_sets.set(/[a-z]/, 26);
pw_sets.set(/[A-Z]/, 26);
pw_sets.set(/[0-9]/, 10);
pw_sets.set(/[^\w]/, 32);
function pw_strength(pw) {
  var set_size = 0;
  pw_sets.each(function (e) {
    if(pw.match(eval(e[0]))) {
      set_size += e[1];
    }
  });
  return Math.pow(set_size,pw.length)/1000.000/86400.0000/365.000;
}

function pw_days_to_crack(years)
{
  if(years > 100)
    return (years/100).toFixed(0) + " " + $('date_centuries').value;
  if(years > 1)
    return years.toFixed(0) + " " + $('date_years').value;
  days = years*365;
  if(days > 30)
    return (days/30).toFixed(0) + " " + $('date_months').value;
  if(days > 7)
    return (days/7).toFixed(0) + " " + $('date_weeks').value;
  if(days < 1 && days*24 > 1)
    return (days*24).toFixed(0) + " " + $('date_hours').value;
  if(days < 1 && days*24*60 > 1)
    return (days*24*60).toFixed(0) + " " + $('date_minutes').value;
  if(days < 1)
    return (days*24*60*60).toFixed(0) + " " + $('date_seconds').value;
  return days.toFixed(0) + " " + $('date_days').value;
}

function pw_bar_class(pw, min_strength) {
  $('pw_time_to_crack').show();
  if(pw.length == 0) {
    $('pw_time').innerHTML = "0 " + $('date_seconds').value;
    return 0;
  }
  if(pw == $('user_login').value) {
    $('pw_time').innerHTML = "a human being";
    return 0;
  }
  var s = pw_strength(pw);
  $('pw_time').innerHTML = pw_days_to_crack(s);
  if(s > min_strength*10)
    return "pw_bar_100";
  if(s >= min_strength)
    return "pw_bar_75";
  if(s > (min_strength/2))
    return "pw_bar_50";
  if(s < (min_strength/2))
    return "pw_bar_25";
}
function set_pw_bar(password, min_strength) {
  $('pw_bar').removeClassName('pw_bar_25');
  $('pw_bar').removeClassName('pw_bar_50');
  $('pw_bar').removeClassName('pw_bar_75');
  $('pw_bar').removeClassName('pw_bar_100');
  $('pw_bar').addClassName(pw_bar_class(password, min_strength));
}
<commit_msg>new password meter algorithm checks for the worst dictionary words, repetitions and other weaknesses. does not try to predict how long it will take to crack because we can't know. fixes #649<commit_after>String.prototype.strReverse = function() {
  var newstring = "";
  for (var s=0; s < this.length; s++) {
    newstring = this.charAt(s) + newstring;
  }
  return newstring;
  //strOrig = ' texttotrim ';
  //strReversed = strOrig.revstring();
};
// http://www.whatsmypass.com/?p=415
var top_500_worst_passwords = ["123456", "porsche", "firebird", "prince", "rosebud", "password", "guitar", "butter", "beach", "jaguar", "12345678", "chelsea", "united", "amateur",
"great", "1234", "black", "turtle", "7777777", "cool", "pussy", "diamond", "steelers", "muffin", "cooper", "12345", "nascar", "tiffany", "redsox", "1313", "dragon", "jackson",
"zxcvbn", "star", "scorpio", "qwerty", "cameron", "tomcat", "testing", "mountain", "696969", "654321", "golf", "shannon", "madison", "mustang", "computer", "bond007", "murphy",
"987654", "letmein", "amanda", "bear", "frank", "brazil", "baseball", "wizard", "tiger", "hannah", "lauren", "master", "xxxxxxxx", "doctor", "dave", "japan", "michael", "money",
"gateway", "eagle1", "naked", "football", "phoenix", "gators", "11111", "squirt", "shadow", "mickey", "angel", "mother", "stars", "monkey", "bailey", "junior", "nathan", "apple",
"abc123", "knight", "thx1138", "raiders", "alexis", "pass", "iceman", "porno", "steve", "aaaa", "fuckme", "tigers", "badboy", "forever", "bonnie", "6969", "purple", "debbie",
"angela", "peaches", "jordan", "andrea", "spider", "viper", "jasmine", "harley", "horny", "melissa", "ou812", "kevin", "ranger", "dakota", "booger", "jake", "matt", "iwantu",
"aaaaaa", "1212", "lovers", "qwertyui", "jennifer", "player", "flyers", "suckit", "danielle", "hunter", "sunshine", "fish", "gregory", "beaver", "fuck", "morgan", "porn", "buddy", "4321", "2000",
"starwars", "matrix", "whatever", "4128", "test", "boomer", "teens", "young", "runner", "batman", "cowboys", "scooby", "nicholas", "swimming", "trustno1", "edward", "jason", "lucky", "dolphin",
"thomas", "charles", "walter", "helpme", "gordon", "tigger", "girls", "cumshot", "jackie", "casper", "robert", "booboo", "boston", "monica", "stupid", "access", "coffee", "braves", "midnight",
"shit", "love", "xxxxxx", "yankee", "college", "saturn", "buster", "bulldog", "lover", "baby", "gemini", "1234567", "ncc1701", "barney", "cunt", "apples", "soccer", "rabbit", "victor", "brian",
"august", "hockey", "peanut", "tucker", "mark", "3333", "killer", "john", "princess", "startrek", "canada", "george", "johnny", "mercedes", "sierra", "blazer", "sexy", "gandalf", "5150", "leather",
"cumming", "andrew", "spanky", "doggie", "232323", "hunting", "charlie", "winter", "zzzzzz", "4444", "kitty", "superman", "brandy", "gunner", "beavis", "rainbow", "asshole", "compaq", "horney", "bigcock",
"112233", "fuckyou", "carlos", "bubba", "happy", "arthur", "dallas", "tennis", "2112", "sophie", "cream", "jessica", "james", "fred", "ladies", "calvin", "panties", "mike", "johnson", "naughty", "shaved",
"pepper", "brandon", "xxxxx", "giants", "surfer", "1111", "fender", "tits", "booty", "samson", "austin", "anthony", "member", "blonde", "kelly", "william", "blowme", "boobs", "fucked", "paul", "daniel",
"ferrari", "donald", "golden", "mine", "golfer", "cookie", "bigdaddy", "0", "king", "summer", "chicken", "bronco", "fire", "racing", "heather", "maverick", "penis", "sandra", "5555", "hammer", "chicago",
"voyager", "pookie", "eagle", "yankees", "joseph", "rangers", "packers", "hentai", "joshua", "diablo", "birdie", "einstein", "newyork", "maggie", "sexsex", "trouble", "dolphins", "little", "biteme", "hardcore",
"white", "0", "redwings", "enter", "666666", "topgun", "chevy", "smith", "ashley", "willie", "bigtits", "winston", "sticky", "thunder", "welcome", "bitches", "warrior", "cocacola", "cowboy", "chris", "green", "sammy",
"animal", "silver", "panther", "super", "slut", "broncos", "richard", "yamaha", "qazwsx", "8675309", "private", "fucker", "justin", "magic", "zxcvbnm", "skippy", "orange", "banana", "lakers", "nipples", "marvin", "merlin",
"driver", "rachel", "power", "blondes", "michelle", "marine", "slayer", "victoria", "enjoy", "corvette", "angels", "scott", "asdfgh", "girl", "bigdog", "fishing", "2222", "vagina", "apollo", "cheese", "david", "asdf", "toyota",
"parker", "matthew", "maddog", "video", "travis", "qwert", "121212", "hooters", "london", "hotdog", "time", "patrick", "wilson", "7777", "paris", "sydney", "martin", "butthead", "marlboro", "rock", "women", "freedom", "dennis",
"srinivas", "xxxx", "voodoo", "ginger", "fucking", "internet", "extreme", "magnum", "blowjob", "captain", "action", "redskins", "juice", "nicole", "bigdick", "carter", "erotic", "abgrtyu", "sparky", "chester", "jasper", "dirty",
"777777", "yellow", "smokey", "monster", "ford", "dreams", "camaro", "xavier", "teresa", "freddy", "maxwell", "secret", "steven", "jeremy", "arsenal", "music", "dick", "viking", "11111111", "access14", "rush2112", "falcon", "snoopy",
"bill", "wolf", "russia", "taylor", "blue", "crystal", "nipple", "scorpion", "111111", "eagles", "peter", "iloveyou", "rebecca", "131313", "winner", "pussies", "alex", "tester", "123123", "samantha", "cock", "florida", "mistress", "bitch",
"house", "beer", "eric", "phantom", "hello", "miller", "rocket", "legend", "billy", "scooter", "flower", "theman", "movie", "6666", "please", "jack", "oliver", "success", "albert"];
/* proudly stolen from http://www.passwordmeter.com/pwd_meter.zip (GPL v2) */
function pw_bar_class_and_complexity(pwd, min_strength) {
  var nScore = 0;
  var nLength = 0;
  var nAlphaUC = 0;
  var nAlphaLC = 0;
  var nNumber = 0;
  var nSymbol = 0;
  var nMidChar = 0;
  var nRequirements = 0;
  var nAlphasOnly = 0;
  var nNumbersOnly = 0;
  var nRepChar = 0;
  var nConsecAlphaUC = 0;
  var nConsecAlphaLC = 0;
  var nConsecNumber = 0;
  var nConsecSymbol = 0;
  var nConsecCharType = 0;
  var nSeqAlpha = 0;
  var nSeqNumber = 0;
  var nSeqChar = 0;
  var nReqChar = 0;
  var nReqCharType = 3;
  var nMultLength = 4;
  var nMultAlphaUC = 3;
  var nMultAlphaLC = 3;
  var nMultNumber = 4;
  var nMultSymbol = 6;
  var nMultMidChar = 2;
  var nMultRequirements = 2;
  var nMultRepChar = 1;
  var nMultConsecAlphaUC = 2;
  var nMultConsecAlphaLC = 2;
  var nMultConsecNumber = 2;
  var nMultConsecSymbol = 1;
  var nMultConsecCharType = 0;
  var nMultSeqAlpha = 3;
  var nMultSeqNumber = 3;
  var nTmpAlphaUC = "";
  var nTmpAlphaLC = "";
  var nTmpNumber = "";
  var nTmpSymbol = "";
  var sAlphas = "abcdefghijklmnopqrstuvwxyz";
  var sNumerics = "01234567890";
  var sComplexity = "Too Short";
  var nMinPwdLen = 5 + min_strength;

  nScore = parseInt(pwd.length * nMultLength);
  nLength = pwd.length;
  var arrPwd = pwd.replace (/\s+/g,"").split(/\s*/);
  var arrPwdLen = arrPwd.length;

  /* Loop through password to check for Symbol, Numeric, Lowercase and Uppercase pattern matches */
  for (var a=0; a < arrPwdLen; a++) {
    if (arrPwd[a].match(new RegExp(/[A-Z]/g))) {
      if (nTmpAlphaUC !== "") { if ((nTmpAlphaUC + 1) == a) { nConsecAlphaUC++; nConsecCharType++; } }
      nTmpAlphaUC = a;
      nAlphaUC++;
    }
    else if (arrPwd[a].match(new RegExp(/[a-z]/g))) {
      if (nTmpAlphaLC !== "") { if ((nTmpAlphaLC + 1) == a) { nConsecAlphaLC++; nConsecCharType++; } }
      nTmpAlphaLC = a;
      nAlphaLC++;
    }
    else if (arrPwd[a].match(new RegExp(/[0-9]/g))) {
      if (a > 0 && a < (arrPwdLen - 1)) { nMidChar++; }
      if (nTmpNumber !== "") { if ((nTmpNumber + 1) == a) { nConsecNumber++; nConsecCharType++; } }
      nTmpNumber = a;
      nNumber++;
    }
    else if (arrPwd[a].match(new RegExp(/[^a-zA-Z0-9_]/g))) {
      if (a > 0 && a < (arrPwdLen - 1)) { nMidChar++; }
      if (nTmpSymbol !== "") { if ((nTmpSymbol + 1) == a) { nConsecSymbol++; nConsecCharType++; } }
      nTmpSymbol = a;
      nSymbol++;
    }
    /* Internal loop through password to check for repeated characters */
    for (var b=0; b < arrPwdLen; b++) {
      if (arrPwd[a].toLowerCase() == arrPwd[b].toLowerCase() && a != b) { nRepChar++; }
    }
  }

  /* Check for sequential alpha string patterns (forward and reverse) */
  for (var s=0; s < 23; s++) {
    var sFwd = sAlphas.substring(s,parseInt(s+3));
    var sRev = sFwd.strReverse();
    if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) { nSeqAlpha++; nSeqChar++;}
  }

  /* Check for sequential numeric string patterns (forward and reverse) */
  for (var s=0; s < 8; s++) {
    var sFwd = sNumerics.substring(s,parseInt(s+3));
    var sRev = sFwd.strReverse();
    if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) { nSeqNumber++; nSeqChar++;}
  }

  /* Modify overall score value based on usage vs requirements */

  /* General point assignment */
  if (nAlphaUC > 0 && nAlphaUC < nLength) {
    nScore = parseInt(nScore + ((nLength - nAlphaUC) * 2));
  }
  if (nAlphaLC > 0 && nAlphaLC < nLength) {
    nScore = parseInt(nScore + ((nLength - nAlphaLC) * 2));
  }
  if (nNumber > 0 && nNumber < nLength) {
    nScore = parseInt(nScore + (nNumber * nMultNumber));
  }
  if (nSymbol > 0) {
    nScore = parseInt(nScore + (nSymbol * nMultSymbol));
  }
  if (nMidChar > 0) {
    nScore = parseInt(nScore + (nMidChar * nMultMidChar));
  }

  /* Point deductions for poor practices */
  if ((nAlphaLC > 0 || nAlphaUC > 0) && nSymbol === 0 && nNumber === 0) {  // Only Letters
    nScore = parseInt(nScore - nLength);
    nAlphasOnly = nLength;
  }
  if (nAlphaLC === 0 && nAlphaUC === 0 && nSymbol === 0 && nNumber > 0) {  // Only Numbers
    nScore = parseInt(nScore - nLength);
    nNumbersOnly = nLength;
  }
  // if (nRepChar > 0) {  // Same character exists more than once
  //   nScore = parseInt(nScore - (nRepChar * nRepChar));
  // }
  if (nConsecAlphaUC > 0) {  // Consecutive Uppercase Letters exist
    nScore = parseInt(nScore - (nConsecAlphaUC * nMultConsecAlphaUC));
  }
  if (nConsecAlphaLC > 0) {  // Consecutive Lowercase Letters exist
    nScore = parseInt(nScore - (nConsecAlphaLC * nMultConsecAlphaLC));
  }
  if (nConsecNumber > 0) {  // Consecutive Numbers exist
    nScore = parseInt(nScore - (nConsecNumber * nMultConsecNumber));
  }
  if (nSeqAlpha > 0) {  // Sequential alpha strings exist (3 characters or more)
    nScore = parseInt(nScore - (nSeqAlpha * nMultSeqAlpha));
  }
  if (nSeqNumber > 0) {  // Sequential numeric strings exist (3 characters or more)
    nScore = parseInt(nScore - (nSeqNumber * nMultSeqNumber));
  }

  /* Determine complexity based on overall score */
  sPwBarClass = ""
  if (nScore > 100) { nScore = 100; } else if (nScore < 0) { nScore = 0; }
  if (nScore >= 0 && nScore < 20) { sComplexity = "Very Weak"; }
  else if (nScore >= 20 && nScore < 40) { sComplexity = "Weak"; sPwBarClass = "pw_bar_25"; }
  else if (nScore >= 40 && nScore < 60) { sComplexity = "Better";  sPwBarClass = "pw_bar_50"; }
  else if (nScore >= 60 && nScore < 80) { sComplexity = "Strong";  sPwBarClass = "pw_bar_75"; }
  else if (nScore >= 80 && nScore <= 100) { sComplexity = "Very Strong";  sPwBarClass = "pw_bar_100"; }

  var sLogin = $('user_login').value;
  if (pwd.include(sLogin))
  {
    sPwBarClass = "";
    sComplexity = "Very Weak (contains login name)";
  }
  top_500_worst_passwords.each(function(bad_pwd) {
     if (pwd.include(bad_pwd) && (pwd.length - bad_pwd.length < 3))
     {
       sPwBarClass = "";
       sComplexity = "Very Weak (too common)";
     }
   });

  return [sPwBarClass, sComplexity];
}

function set_pw_bar(password, min_strength) {
  $('pw_bar').removeClassName('pw_bar_25');
  $('pw_bar').removeClassName('pw_bar_50');
  $('pw_bar').removeClassName('pw_bar_75');
  $('pw_bar').removeClassName('pw_bar_100');

  var complexity_results = pw_bar_class_and_complexity(password, min_strength);
  var pw_bar_class = complexity_results[0];
  var pw_complexity_text = complexity_results[1];

  $('pw_time_to_crack').show();
  $('pw_time_to_crack').innerHTML = pw_complexity_text;
  $('pw_bar').addClassName(pw_bar_class);
}
<|endoftext|>


<commit_before>Object.forEach = function (object, callback) {
    for (var key in object) {
        if (object.hasOwnProperty(key))
            callback.call(object, key, object[key]);
    }
};
Object.every = function (object, callback) {
    for (var key in object) {
        if (object.hasOwnProperty(key))
            if (callback.call(object, key, object[key]) === false) return false;
    }
    return true;
};
Object.some = function (object, callback) {
    var status = false;
    for (var key in object) {
        if (object.hasOwnProperty(key))
            status = callback.call(object, key, object[key]) || status;
    }
    return status;
};
Object.clone = function (o) {
    if (o === null || typeof(o) !== 'object') return o;

    var objNew = o.constructor();

    for (var key in o)
        objNew[key] = Object.clone(o[key]);

    return objNew;
};
Object.merge = function (o1, o2) {
    var objNew = Object.clone(o1);
    for (var p in o2) {
        if (o2[p] && o2[p].constructor === Object) {
            if (!o1[p]) o1[p] = {};
            objNew[p] = Object.merge(o1[p], o2[p]);
        } else {
            objNew[p] = o2[p];
        }
    }
    return objNew;
};
document.elem = function (elemname, attributes, text) {
    if (typeof attributes === 'string') {
        text = attributes;
        attributes = null;
    }
    if (elemname === 'textElem') return document.createTextNode(text);
    return document.createElement(elemname).attrib(attributes).setText(text);
};
document.getElem = document.querySelector;
document.getElemAll = document.querySelectorAll;
document.delElem = function (element) {
    if (typeof element === 'string') {
        element = document.getElemAll(element);
    }
    if (element.each) {
        element.each(function () {
            if (this.parentNode) this.parentNode.removeChild(this);
        });
    } else if (element && element.parentNode) {
        element.parentNode.removeChild(element);
    }
};
document.ready = function (callback) {
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", callback);
    } else {
        document.onreadystatechange = function () {
            if (document.readyState == "interactive") callback();
        }
    }
};
Element.prototype.getElem = Element.prototype.querySelector;
Element.prototype.getElemAll = Element.prototype.querySelectorAll;
Element.prototype.del = function () {
    var parent = this.parentNode;
    if (parent) parent.removeChild(this);
    return parent;
};
Element.prototype.elem = function (elemname, attr, text, returnparent) {
    if (typeof elemname !== 'string') {
        var _that = this;
        [].concat(elemname).forEach(function (element) {
            _that.appendChild(element);
        });
        return this;
    }
    var elem = document.elem(elemname, attr, text);
    this.appendChild(elem);
    return (returnparent !== null && returnparent) ? this : ['br', 'hr', 'textElem'].indexOf(elemname) === -1 ? elem : returnparent === false ? elem : this;
};
Element.prototype.siblings = function () {
    return this.parentElement.children;
};
Element.prototype.up = function () {
    return this.parentElement;
}
Element.prototype.attrib = function (attribute, value) {
    if (attribute) {
        var _this = this;
        var setOrRemove = function (key, value) {
            value !== null ? _this.setAttribute(key, value) : _this.removeAttribute(key);
        };
        if (typeof attribute === "object") {
            Object.forEach(attribute, setOrRemove);
        } else if (typeof attribute === 'string') {
            setOrRemove(attribute, value);
        }
    }
    return this;
};
Element.prototype.setText = function (text) {
    if (text) {
        this.textContent = text;
    }
    return this;
};
Element.prototype.clearElem = function () {
    if (this.textContent !== null) {
        this.textContent = '';
    }
    while (this.firstChild) {
        this.removeChild(this.firstChild);
    }
    return this;
};
Element.prototype.on = function (event, listener, useCapture) {
    if (this.attachEvent) {
        this.attachEvent(event, listener);
    } else {
        this.addEventListener(event, listener, useCapture);
    }
    return this;
};
Element.prototype.off = function (event, listener, useCapture) {
    if (this.detachEvent) {
        this.detachEvent(event, listener);
    } else {
        this.removeEventListener(event, listener, useCapture);
    }
    return this;
};
Element.prototype.addClass = function (className) {
    var classes = this.className.split(' ');
    if (classes.indexOf(className) === -1) {
        classes.push(className);
        this.className = classes.join(' ');
    }
    return this;
};
Element.prototype.removeClass = function (className) {
    var classes = this.className.split(' ');
    var index = classes.indexOf(className);
    if (index !== -1) {
        classes.splice(index, 1);
        this.className = classes.join(' ');
    }
    return this;
};
Element.prototype.hasClass = function (className) {
    return this.className.split(' ').indexOf(className) !== -1;
};
NodeList.prototype.forEach = function (callback) {
    for (var i = 0; i < this.length; i++) {
        callback.call(this[i], i);
    }
};
NodeList.prototype.every = function (callback) {
    for (var i = 0; i < this.length; i++) {
        if (callback.call(this[i]) === false) return false;
    }
    return true;
};
NodeList.prototype.some = function (callback) {
    var status = false;
    for (var i = 0; i < this.length; i++) {
        status = callback.call(this[i]) || status;
    }
    return status;
};
NodeList.prototype.attrib = function (attribute, value) {
    this.each(function () {
        this.attrib(attribute, value)
    });
    return this;
};
NodeList.prototype.elem = function (elemname, attr, text, returnparent) {
    var rand = Math.random() * 10000, name = "data-elemjs-attachnodelist";
    this.each(function () {
        this.elem(elemname, attr, text, returnparent).attrib(name, rand);
    });
    return document.getElemAll("[" + name + "='" + rand + "']").attrib(name, null);
};
NodeList.prototype.del = function () {
    var rand = Math.random() * 10000, name = "data-elemjs-attachnodelist";
    this.each(function () {
        this.del().attrib(name, rand);
    });
    return document.getElemAll("[" + name + "='" + rand + "']").attrib(name, null);
};
NodeList.prototype.getElem = function (selector) {
    var rand = Math.random() * 10000, name = "data-elemjs-attachnodelist";
    this.each(function () {
        var temp = this.getElem(selector);
        if (temp !== null)temp.attrib(name, rand);
    });
    return document.getElemAll("[" + name + "='" + rand + "']").attrib(name, null);
};
NodeList.prototype.getElemAll = function (selector) {
    var rand = Math.random() * 10000, name = "data-elemjs-attachnodelist";
    this.each(function () {
        this.getElemAll(selector).attrib(name, rand);
    });
    return document.getElemAll("[" + name + "='" + rand + "']").attrib(name, null);
};
NodeList.prototype.on = function (event, listener, useCapture) {
    this.each(function () {
        this.on(event, listener, useCapture);
    });
    return this;
};
NodeList.prototype.off = function (event, listener, useCapture) {
    this.each(function () {
        this.off(event, listener, useCapture);
    });
    return this;
};
NodeList.prototype.toArray = function () {
    var arr = [];
    for (var i = this.length; i--; arr.unshift(this[i]));
    return arr;
};
['section', 'nav', 'article', 'aside', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'footer', 'address', 'main', 'p', 'hr', 'pre', 'ol', 'ul', 'li', 'div', 'a', 'em', 'strong', 'code', 'span', 'br', 'img', 'svg', 'table', 'tbody', 'thead', 'tfoot', 'tr', 'td', 'th', 'form', 'label', 'input', 'button', 'select', 'option', 'textarea', 'textElem'].map(function (elemname) {
    Element.prototype[elemname] = function (attr, text, returnparent) {
        return this.elem(elemname, attr, text, returnparent);
    };
    document[elemname] = function (attr, text) {
        return this.elem(elemname, attr, text);
    };
    NodeList.prototype[elemname] = function (attr, text, returnparent) {
        return this.elem(elemname, attr, text, returnparent);
    }
});
Window.http = {
    request: function (config, onSuccess, onError) {
        var defaults = { method: 'GET', async: true, headers: {} };
        var options = Object.merge(defaults, config);
        var xhr = new XMLHttpRequest();
        xhr.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                if (typeof onSuccess === 'function') onSuccess(this.responseText, this.status, this);
            } else {
                if (typeof onError === 'function') onError(this.responseText, this.status, this);
            }
        };
        xhr.onerror = function () {
            if (typeof onError === 'function') onError(this.statusText, this.status, this);
        };
        xhr.open(options.method, options.url, options.aSync);
        if (options.headers !== null && typeof options.headers === 'object')
            Object.forEach(options.headers, function (key, value) {
                xhr.setRequestHeader(key, value);
            });
        if (options.data && typeof options.data === "object" && config.headers["Content-type"] === "application/x-www-form-urlencoded") {
            options.data = Window.http.serialize(options.data);
        }
        xhr.send(options.data);
        return xhr;
    },
    GET: function (config, onSuccess, onError) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.method = "GET";
        if (config.data && typeof config.data === 'object') {
            config.url += document.a({href: config.url}).search ? '&' : '?';
            config.url += Window.http.serialize(config.data);
            delete config.data;
        }
        return Window.http.request(config, onSuccess, onError);
    },
    POST: function (config, onSuccess, onError) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.method = "POST";
        config.headers = config.headers || {};
        config.headers["Content-type"] = config.headers["Content-type"] || "application/x-www-form-urlencoded";
        return Window.http.request(config, onSuccess, onError);
    },
    PUT: function (config, onSuccess, onError) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.method = "PUT";
        config.headers = config.headers || {};
        config.headers["Content-type"] = config.headers["Content-type"] || "application/x-www-form-urlencoded";
        return Window.http.request(config, onSuccess, onError);
    },
    DELETE: function (config, onSuccess, onError) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.method = "DELETE";
        return Window.http.request(config, onSuccess, onError);
    },
    serialize: function (obj, prefix) {
        var str = [];
        Object.forEach(obj, function (key, value) {
            var k = prefix ? prefix + "[" + key + "]" : key, v = value;
            str.push(typeof v == "object" ?
                Window.http.serialize(v, k) :
                encodeURIComponent(k) + "=" + encodeURIComponent(v));
        });
        return str.join("&");
    },
    load: function (config) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.src = config.src || config.url;
        delete config.url;
        if (config.data && typeof config.data === 'object') {
            config.src += document.a({href: config.src}).search ? '&' : '?';
            config.src += Window.http.serialize(config.data);
            delete config.data;
        }
        if (config.id) {
            var toDelete = document.getElem("#" + config.id);
            if (toDelete !== null) {
                toDelete.del();
            }
        }
        return document.getElem("head").elem("script", config);
    }
};
<commit_msg>added detection to document.ready to see if document was ready before this method was called<commit_after>Object.forEach = function (object, callback) {
    for (var key in object) {
        if (object.hasOwnProperty(key))
            callback.call(object, key, object[key]);
    }
};
Object.every = function (object, callback) {
    for (var key in object) {
        if (object.hasOwnProperty(key))
            if (callback.call(object, key, object[key]) === false) return false;
    }
    return true;
};
Object.some = function (object, callback) {
    var status = false;
    for (var key in object) {
        if (object.hasOwnProperty(key))
            status = callback.call(object, key, object[key]) || status;
    }
    return status;
};
Object.clone = function (o) {
    if (o === null || typeof(o) !== 'object') return o;

    var objNew = o.constructor();

    for (var key in o)
        objNew[key] = Object.clone(o[key]);

    return objNew;
};
Object.merge = function (o1, o2) {
    var objNew = Object.clone(o1);
    for (var p in o2) {
        if (o2[p] && o2[p].constructor === Object) {
            if (!o1[p]) o1[p] = {};
            objNew[p] = Object.merge(o1[p], o2[p]);
        } else {
            objNew[p] = o2[p];
        }
    }
    return objNew;
};
document.elem = function (elemname, attributes, text) {
    if (typeof attributes === 'string') {
        text = attributes;
        attributes = null;
    }
    if (elemname === 'textElem') return document.createTextNode(text);
    return document.createElement(elemname).attrib(attributes).setText(text);
};
document.getElem = document.querySelector;
document.getElemAll = document.querySelectorAll;
document.delElem = function (element) {
    if (typeof element === 'string') {
        element = document.getElemAll(element);
    }
    if (element.each) {
        element.each(function () {
            if (this.parentNode) this.parentNode.removeChild(this);
        });
    } else if (element && element.parentNode) {
        element.parentNode.removeChild(element);
    }
};
document.ready = function (callback) {
    if (document.readyState == "complete" || document.readyState == "loaded" || document.readyState == "interactive") {
        setTimeout(callback,1);
    }else if (document.addEventListener) {
            document.addEventListener("DOMContentLoaded", callback);
    } else {
        document.onreadystatechange = function () {
            if (document.readyState == "interactive") callback();
        }
    }
};
Element.prototype.getElem = Element.prototype.querySelector;
Element.prototype.getElemAll = Element.prototype.querySelectorAll;
Element.prototype.del = function () {
    var parent = this.parentNode;
    if (parent) parent.removeChild(this);
    return parent;
};
Element.prototype.elem = function (elemname, attr, text, returnparent) {
    if (typeof elemname !== 'string') {
        var _that = this;
        [].concat(elemname).forEach(function (element) {
            _that.appendChild(element);
        });
        return this;
    }
    var elem = document.elem(elemname, attr, text);
    this.appendChild(elem);
    return (returnparent !== null && returnparent) ? this : ['br', 'hr', 'textElem'].indexOf(elemname) === -1 ? elem : returnparent === false ? elem : this;
};
Element.prototype.siblings = function () {
    return this.parentElement.children;
};
Element.prototype.up = function () {
    return this.parentElement;
}
Element.prototype.attrib = function (attribute, value) {
    if (attribute) {
        var _this = this;
        var setOrRemove = function (key, value) {
            value !== null ? _this.setAttribute(key, value) : _this.removeAttribute(key);
        };
        if (typeof attribute === "object") {
            Object.forEach(attribute, setOrRemove);
        } else if (typeof attribute === 'string') {
            setOrRemove(attribute, value);
        }
    }
    return this;
};
Element.prototype.setText = function (text) {
    if (text) {
        this.textContent = text;
    }
    return this;
};
Element.prototype.clearElem = function () {
    if (this.textContent !== null) {
        this.textContent = '';
    }
    while (this.firstChild) {
        this.removeChild(this.firstChild);
    }
    return this;
};
Element.prototype.on = function (event, listener, useCapture) {
    if (this.attachEvent) {
        this.attachEvent(event, listener);
    } else {
        this.addEventListener(event, listener, useCapture);
    }
    return this;
};
Element.prototype.off = function (event, listener, useCapture) {
    if (this.detachEvent) {
        this.detachEvent(event, listener);
    } else {
        this.removeEventListener(event, listener, useCapture);
    }
    return this;
};
Element.prototype.addClass = function (className) {
    var classes = this.className.split(' ');
    if (classes.indexOf(className) === -1) {
        classes.push(className);
        this.className = classes.join(' ');
    }
    return this;
};
Element.prototype.removeClass = function (className) {
    var classes = this.className.split(' ');
    var index = classes.indexOf(className);
    if (index !== -1) {
        classes.splice(index, 1);
        this.className = classes.join(' ');
    }
    return this;
};
Element.prototype.hasClass = function (className) {
    return this.className.split(' ').indexOf(className) !== -1;
};
NodeList.prototype.forEach = function (callback) {
    for (var i = 0; i < this.length; i++) {
        callback.call(this[i], i);
    }
};
NodeList.prototype.every = function (callback) {
    for (var i = 0; i < this.length; i++) {
        if (callback.call(this[i]) === false) return false;
    }
    return true;
};
NodeList.prototype.some = function (callback) {
    var status = false;
    for (var i = 0; i < this.length; i++) {
        status = callback.call(this[i]) || status;
    }
    return status;
};
NodeList.prototype.attrib = function (attribute, value) {
    this.each(function () {
        this.attrib(attribute, value)
    });
    return this;
};
NodeList.prototype.elem = function (elemname, attr, text, returnparent) {
    var rand = Math.random() * 10000, name = "data-elemjs-NL-elem";
    this.each(function () {
        this.elem(elemname, attr, text, returnparent).attrib(name, rand);
    });
    return document.getElemAll("[" + name + "='" + rand + "']").attrib(name, null);
};
NodeList.prototype.del = function () {
    var rand = Math.random() * 10000, name = "data-elemjs-NL-del";
    this.each(function () {
        this.del().attrib(name, rand);
    });
    return document.getElemAll("[" + name + "='" + rand + "']").attrib(name, null);
};
NodeList.prototype.getElem = function (selector) {
    var rand = Math.random() * 10000, name = "data-elemjs-NL-getElem";
    this.each(function () {
        var temp = this.getElem(selector);
        if (temp !== null)temp.attrib(name, rand);
    });
    return document.getElemAll("[" + name + "='" + rand + "']").attrib(name, null);
};
NodeList.prototype.getElemAll = function (selector) {
    var rand = Math.random() * 10000, name = "data-elemjs-NL-getElemAll";
    this.each(function () {
        this.getElemAll(selector).attrib(name, rand);
    });
    return document.getElemAll("[" + name + "='" + rand + "']").attrib(name, null);
};
NodeList.prototype.on = function (event, listener, useCapture) {
    this.each(function () {
        this.on(event, listener, useCapture);
    });
    return this;
};
NodeList.prototype.off = function (event, listener, useCapture) {
    this.each(function () {
        this.off(event, listener, useCapture);
    });
    return this;
};
NodeList.prototype.toArray = function () {
    var arr = [];
    for (var i = this.length; i--; arr.unshift(this[i]));
    return arr;
};
['section', 'nav', 'article', 'aside', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'footer', 'address', 'main', 'p', 'hr', 'pre', 'ol', 'ul', 'li', 'div', 'a', 'em', 'strong', 'code', 'span', 'br', 'img', 'svg', 'table', 'tbody', 'thead', 'tfoot', 'tr', 'td', 'th', 'form', 'label', 'input', 'button', 'select', 'option', 'textarea', 'textElem'].map(function (elemname) {
    Element.prototype[elemname] = function (attr, text, returnparent) {
        return this.elem(elemname, attr, text, returnparent);
    };
    document[elemname] = function (attr, text) {
        return this.elem(elemname, attr, text);
    };
    NodeList.prototype[elemname] = function (attr, text, returnparent) {
        return this.elem(elemname, attr, text, returnparent);
    }
});
Window.http = {
    request: function (config, onSuccess, onError) {
        var defaults = { method: 'GET', async: true, headers: {} };
        var options = Object.merge(defaults, config);
        var xhr = new XMLHttpRequest();
        xhr.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                if (typeof onSuccess === 'function') onSuccess(this.responseText, this.status, this);
            } else {
                if (typeof onError === 'function') onError(this.responseText, this.status, this);
            }
        };
        xhr.onerror = function () {
            if (typeof onError === 'function') onError(this.statusText, this.status, this);
        };
        xhr.open(options.method, options.url, options.aSync);
        if (options.headers !== null && typeof options.headers === 'object')
            Object.forEach(options.headers, function (key, value) {
                xhr.setRequestHeader(key, value);
            });
        if (options.data && typeof options.data === "object" && config.headers["Content-type"] === "application/x-www-form-urlencoded") {
            options.data = Window.http.serialize(options.data);
        }
        xhr.send(options.data);
        return xhr;
    },
    GET: function (config, onSuccess, onError) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.method = "GET";
        if (config.data && typeof config.data === 'object') {
            config.url += document.a({href: config.url}).search ? '&' : '?';
            config.url += Window.http.serialize(config.data);
            delete config.data;
        }
        return Window.http.request(config, onSuccess, onError);
    },
    POST: function (config, onSuccess, onError) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.method = "POST";
        config.headers = config.headers || {};
        config.headers["Content-type"] = config.headers["Content-type"] || "application/x-www-form-urlencoded";
        return Window.http.request(config, onSuccess, onError);
    },
    PUT: function (config, onSuccess, onError) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.method = "PUT";
        config.headers = config.headers || {};
        config.headers["Content-type"] = config.headers["Content-type"] || "application/x-www-form-urlencoded";
        return Window.http.request(config, onSuccess, onError);
    },
    DELETE: function (config, onSuccess, onError) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.method = "DELETE";
        return Window.http.request(config, onSuccess, onError);
    },
    serialize: function (obj, prefix) {
        var str = [];
        Object.forEach(obj, function (key, value) {
            var k = prefix ? prefix + "[" + key + "]" : key, v = value;
            str.push(typeof v == "object" ?
                Window.http.serialize(v, k) :
                encodeURIComponent(k) + "=" + encodeURIComponent(v));
        });
        return str.join("&");
    },
    load: function (config) {
        config = (typeof config === "string") ? {url: config} : config || {};
        config.src = config.src || config.url;
        delete config.url;
        if (config.data && typeof config.data === 'object') {
            config.src += document.a({href: config.src}).search ? '&' : '?';
            config.src += Window.http.serialize(config.data);
            delete config.data;
        }
        if (config.id) {
            var toDelete = document.getElem("#" + config.id);
            if (toDelete !== null) {
                toDelete.del();
            }
        }
        return document.getElem("head").elem("script", config);
    }
};
<|endoftext|>