<commit_before>/* global describe, it */
'use strict';

var assert = require('assert');

describe('#requires', function(){
  var requires  = require('../requires.js');
  it('should default to function', function(){
    assert.deepEqual(requires('name - description'), { type : 'function', name : 'name', description : 'description', 'external': false });
    assert.deepEqual(requires('name description'), { type : 'function', name : 'name', description : 'description', 'external': false});
  });

  it('should work for variables with with or without $', function(){
    assert.deepEqual(requires('{variable} $my-variable'), { type : 'variable', name : 'my-variable', 'external': false});
    assert.deepEqual(requires('{variable} my-variable'),  { type : 'variable', name : 'my-variable', 'external': false});
  });

  it('should work with optional variable type if $ is used', function(){
    assert.deepEqual(requires('{variable} my-variable'), { type : 'variable', name : 'my-variable', 'external': false});
    assert.deepEqual(requires('$my-variable'), { type : 'variable', name : 'my-variable', 'external': false});
  });

  it('should work for external requires', function(){
    assert.deepEqual(requires('{variable} extern::lib'), { type : 'variable', name : 'extern::lib', 'external': true});
    assert.deepEqual(requires('extern::lib'), { type : 'function', name : 'extern::lib', 'external': true});
    assert.deepEqual(requires('$extern::lib'), { type : 'variable', name : 'extern::lib', 'external': true});
  });

  it('should work for external requires with url', function(){
    assert.deepEqual(requires('{variable} extern::lib - description <http://url.com>'),
                    {'type': 'variable', 'name': 'extern::lib', 'external':true, 'description': 'description', 'url': 'http://url.com'});
  });

  it.only('should work for name and url', function(){
    assert.deepEqual(requires('SassCore::map-has-key <http://sass-lang.com/documentation/Sass/Script/Functions.html#map_has_key-instance_method>'),
                    {'type': 'function', 'name': 'SassCore::map-has-key', 'external':true, 'url': 'http://sass-lang.com/documentation/Sass/Script/Functions.html#map_has_key-instance_method'});

  });
});

<commit_msg>Fixed a dev typo preventing JS tests from being run<commit_after>/* global describe, it */
'use strict';

var assert = require('assert');

describe('#requires', function(){
  var requires  = require('../requires.js');
  it('should default to function', function(){
    assert.deepEqual(requires('name - description'), { type : 'function', name : 'name', description : 'description', 'external': false });
    assert.deepEqual(requires('name description'), { type : 'function', name : 'name', description : 'description', 'external': false});
  });

  it('should work for variables with with or without $', function(){
    assert.deepEqual(requires('{variable} $my-variable'), { type : 'variable', name : 'my-variable', 'external': false});
    assert.deepEqual(requires('{variable} my-variable'),  { type : 'variable', name : 'my-variable', 'external': false});
  });

  it('should work with optional variable type if $ is used', function(){
    assert.deepEqual(requires('{variable} my-variable'), { type : 'variable', name : 'my-variable', 'external': false});
    assert.deepEqual(requires('$my-variable'), { type : 'variable', name : 'my-variable', 'external': false});
  });

  it('should work for external requires', function(){
    assert.deepEqual(requires('{variable} extern::lib'), { type : 'variable', name : 'extern::lib', 'external': true});
    assert.deepEqual(requires('extern::lib'), { type : 'function', name : 'extern::lib', 'external': true});
    assert.deepEqual(requires('$extern::lib'), { type : 'variable', name : 'extern::lib', 'external': true});
  });

  it('should work for external requires with url', function(){
    assert.deepEqual(requires('{variable} extern::lib - description <http://url.com>'),
                    {'type': 'variable', 'name': 'extern::lib', 'external':true, 'description': 'description', 'url': 'http://url.com'});
  });

  it('should work for name and url', function(){
    assert.deepEqual(requires('SassCore::map-has-key <http://sass-lang.com/documentation/Sass/Script/Functions.html#map_has_key-instance_method>'),
                    {'type': 'function', 'name': 'SassCore::map-has-key', 'external':true, 'url': 'http://sass-lang.com/documentation/Sass/Script/Functions.html#map_has_key-instance_method'});

  });
});

<|endoftext|>


<commit_before>/*
 * main.js is the entry point for the application.
 */
define(function(require) {

	// context is the application context
	// dashboard is the bridge between the application context and the apps
	var context = require('context');
	var dashboard = require('dashboard');

	// Vendor libraries
	var $ = require('jquery');
	var Backbone = require('backbone');
	var underscore = require('underscore');

	// Our libraries
	var FabMo = require('fabmo');
	var FabMoUI = require('fabmo-ui');
	var WheelControl = require('handwheel');

	// Load the apps from the server
	context.apps = new context.models.Apps();
	context.apps.fetch({
		success: function() {
			// Create the menu based on the apps thus retrieved
			context.appMenuView = new context.views.AppMenuView({collection : context.apps, el : '#app_menu_container'});

			// Create a FabMo object for the dashboard
			dashboard.machine = new FabMo(window.location.hostname, window.location.port);
			dashboard.socket = require('websocket').SocketIO();

			// Create a FabMoUI object for the same (but don't recreate it if it already exists)
			if (!dashboard.ui) {
				dashboard.ui= new FabMoUI(dashboard.machine);
			}
			else {
				dashboard.ui.tool = dashboard.machine;
			}

			dashboard.ui.on('error', function(err) {
				$('#modalDialogTitle').text('Error!');
				$('#modalDialogLead').html('
There was an error!
');
				$('#modalDialogMessage').text(err || 'There is no message associated with this error.');
				if(dashboard.machine.status_report.job) {
					$('#modalDialogDetail').html(
						'
' +
						  'Job Name:  ' + dashboard.machine.status_report.job.name + '
' +
						  'Job Description:  ' + dashboard.machine.status_report.job.description +
						'
'
						);
				} else {
					$('#modalDialogDetail').html('
Additional information for this error is unavailable.
');
				}
				$('#modalDialog').foundation('reveal', 'open');
			});

			// Request a status update from the tool
			dashboard.ui.updateStatus();

			// Configure handwheel input
			var wheel = setupHandwheel();

			// Start the application
			router = new context.Router();
			router.setContext(context);

			// Sort of a hack, but works OK.
			$('#spinner').hide();

			// Start backbone routing
			Backbone.history.start();
		}
	});

function setupHandwheel() {

	var wheel = new WheelControl('wheel', {
		wheelSpeed : 1.0,
		labelColor : 'white'
	});

	var SCALE = 0.030;
	var TICKS_MOVE = 20;
	var NUDGE = 0.010;

	var angle = 0.0;
	var speed = 1.0;

	wheel.on('speed', function changeSpeed(data) {
		speed = data.speed;
	});

	wheel.on('move', function makeMove(data) {
		var degrees = data.angle*180.0/Math.PI;
		angle += degrees;
		var distance = Math.abs(angle*SCALE*speed);
		var axis = data.axis;

		if(angle > TICKS_MOVE) {
			angle = 0;
			dashboard.machine.fixed_move('+' + axis, distance, speed*60.0, function(err) {});
		}
		if(angle < -TICKS_MOVE) {
			angle = 0;
			dashboard.machine.fixed_move('-' + axis, distance, speed*60.0, function(err) {});
		}
	});

	wheel.on('release', function quit(data) {
		dashboard.machine.quit(function() {})
	});

	wheel.on('nudge', function nudge(data) {
		dashboard.machine.fixed_move(data.axis, NUDGE, speed*60, function(err) {});
	});
	return wheel;
}

// Kill the currently running job when the modal error dialog is dismissed
$(document).on('close.fndtn.reveal', '[data-reveal]', function (evt) {
  var modal = $(this);
  dashboard.machine.quit(function() {});
});

// Handlers for the home/probe buttons
$('.button-zerox').click(function(e) {dashboard.machine.sbp('ZX', function(){}); });
$('.button-zeroy').click(function(e) {dashboard.machine.sbp('ZY', function(){}); });
$('.button-zeroz').click(function(e) {dashboard.machine.sbp('ZZ', function(){}); });

//Handle collapse of left screen
	$('#icon_colapse').click(function() {
		if ($(window).width() < 640 && !$('#left-menu').hasClass("colapsed")) {
			$('.collapseLeft').show();
		}
		else {
			$('.collapseLeft').hide();
		}
	});

	$('.collapseLeft').click(function(){
		$('.collapseLeft').hide();
		$('#left-menu').addClass("colapsed");
		$('#widget-links-general').addClass("colapsed");
	});
});

<commit_msg>more  relaiable<commit_after>/*
 * main.js is the entry point for the application.
 */
define(function(require) {

	// context is the application context
	// dashboard is the bridge between the application context and the apps
	var context = require('context');
	var dashboard = require('dashboard');

	// Vendor libraries
	var $ = require('jquery');
	var Backbone = require('backbone');
	var underscore = require('underscore');

	// Our libraries
	var FabMo = require('fabmo');
	var FabMoUI = require('fabmo-ui');
	var WheelControl = require('handwheel');

	// Load the apps from the server
	context.apps = new context.models.Apps();
	context.apps.fetch({
		success: function() {
			// Create the menu based on the apps thus retrieved
			context.appMenuView = new context.views.AppMenuView({collection : context.apps, el : '#app_menu_container'});

			// Create a FabMo object for the dashboard
			dashboard.machine = new FabMo(window.location.hostname, window.location.port);
			dashboard.socket = require('websocket').SocketIO();

			// Create a FabMoUI object for the same (but don't recreate it if it already exists)
			if (!dashboard.ui) {
				dashboard.ui= new FabMoUI(dashboard.machine);
			}
			else {
				dashboard.ui.tool = dashboard.machine;
			}

			dashboard.ui.on('error', function(err) {
				$('#modalDialogTitle').text('Error!');
				$('#modalDialogLead').html('
There was an error!
');
				$('#modalDialogMessage').text(err || 'There is no message associated with this error.');
				if(dashboard.machine.status_report.job) {
					$('#modalDialogDetail').html(
						'
' +
						  'Job Name:  ' + dashboard.machine.status_report.job.name + '
' +
						  'Job Description:  ' + dashboard.machine.status_report.job.description +
						'
'
						);
				} else {
					$('#modalDialogDetail').html('
Additional information for this error is unavailable.
');
				}
				$('#modalDialog').foundation('reveal', 'open');
			});

			// Request a status update from the tool
			dashboard.ui.updateStatus();

			// Configure handwheel input
			var wheel = setupHandwheel();

			// Start the application
			router = new context.Router();
			router.setContext(context);

			// Sort of a hack, but works OK.
			$('#spinner').hide();

			// Start backbone routing
			Backbone.history.start();
		}
	});

function setupHandwheel() {

	var wheel = new WheelControl('wheel', {
		wheelSpeed : 1.0,
		labelColor : 'white'
	});

	var SCALE = 0.030;
	var TICKS_MOVE = 20;
	var NUDGE = 0.010;

	var angle = 0.0;
	var speed = 1.0;

	wheel.on('speed', function changeSpeed(data) {
		speed = data.speed;
	});

	wheel.on('move', function makeMove(data) {
		var degrees = data.angle*180.0/Math.PI;
		angle += degrees;
		var distance = Math.abs(angle*SCALE*speed);
		var axis = data.axis;

		if(angle > TICKS_MOVE) {
			angle = 0;
			dashboard.machine.fixed_move('+' + axis, distance, speed*60.0, function(err) {});
		}
		if(angle < -TICKS_MOVE) {
			angle = 0;
			dashboard.machine.fixed_move('-' + axis, distance, speed*60.0, function(err) {});
		}
	});

	wheel.on('release', function quit(data) {
		dashboard.machine.quit(function() {})
	});

	wheel.on('nudge', function nudge(data) {
		dashboard.machine.fixed_move(data.axis, NUDGE, speed*60, function(err) {});
	});
	return wheel;
}

// Kill the currently running job when the modal error dialog is dismissed
$(document).on('close.fndtn.reveal', '[data-reveal]', function (evt) {
  var modal = $(this);
  dashboard.machine.quit(function() {});
});

// Handlers for the home/probe buttons
$('.button-zerox').click(function(e) {dashboard.machine.sbp('ZX', function(){}); });
$('.button-zeroy').click(function(e) {dashboard.machine.sbp('ZY', function(){}); });
$('.button-zeroz').click(function(e) {dashboard.machine.sbp('ZZ', function(){}); });

//Handle collapse of left screen
	$('#icon_colapse').click(function() {
		if ($(window).width() < 640 && $('#widget-links-general').hasClass("colapsed")) {
			$('.collapseLeft').show();
			console.log('you');
		}
		else {
			$('.collapseLeft').hide();
		}
	});

	$('.collapseLeft').click(function(){
		$('.collapseLeft').hide();
		$('#left-menu').addClass("colapsed");
		$('#widget-links-general').addClass("colapsed");
	});
});

<|endoftext|>


<commit_before>/**
 * This module can be used to communicate using HTTP/SOAP
 * to connect to a specific endpoint pass the url to the
 * option variable. otherwise destination will be taken
 * from the message object.
 *
 */
var http = require('http');
var url = require('url');
var logger = require('../logger');

module.exports = {
		/**
		 * method to call web service using SOAP. connect to the web
		 * service and pass the SOAP message
		 * @param message zenith message object
		 * @param option details related to the web service
		 * @param callback
		 */
		callService : function (message, option, callback){

		    var parseURL = url.parse(option.url);
			var wsOptions={
					hostname : parseURL.hostname,
					path : parseURL.path,
					port : parseURL.port,
					method : message.transportHeaders.method,
					agent: false
				};
			var body = '';
			var wsRequest = http.request(wsOptions, function(wsResponse) {
					wsResponse.on('data', function(chunk) {
						//ws reply body
						body = body + chunk;

					});
					wsResponse.on('end', function() {

						//when every thing is done send the message
						//object back
						logger.debug('WSEndPoint', 'Response: ' + body);
						message.body = body;

						message.transportHeaders.statusCode = wsResponse.statusCode;
						message.transportHeaders.headers = wsResponse.headers;
						message.contentType = wsResponse.headers['content-type'];
						callback(null, message);
					});

				});

				wsRequest.on('error', function(er){

					logger.error('WSEndPoint', 'problem with request: ' + er.message);
					//pass the error message
                    callback(er);

				});

				wsRequest.write(message.body);
				wsRequest.end();

		}
}
<commit_msg>add content type<commit_after>/**
 * This module can be used to communicate using HTTP/SOAP
 * to connect to a specific endpoint pass the url to the
 * option variable. otherwise destination will be taken
 * from the message object.
 *
 */
var http = require('http');
var url = require('url');
var logger = require('../logger');

module.exports = {
		/**
		 * method to call web service using SOAP. connect to the web
		 * service and pass the SOAP message
		 * @param message zenith message object
		 * @param option details related to the web service
		 * @param callback
		 */
		callService : function (message, option, callback){

		    var parseURL = url.parse(option.url);
			var wsOptions={
					hostname : parseURL.hostname,
					path : parseURL.path,
					port : parseURL.port,
					method : message.transportHeaders.method,
					headers: message.transportHeaders,
					agent: false
				};
			var body = '';
			var wsRequest = http.request(wsOptions, function(wsResponse) {
					wsResponse.on('data', function(chunk) {
						//ws reply body
						body = body + chunk;

					});
					wsResponse.on('end', function() {

						//when every thing is done send the message
						//object back
						logger.debug('WSEndPoint', 'Response: ' + body);
						message.body = body;

						message.transportHeaders.statusCode = wsResponse.statusCode;
						message.transportHeaders.headers = wsResponse.headers;
						message.contentType = wsResponse.headers['content-type'];
						callback(null, message);
					});

				});

				wsRequest.on('error', function(er){

					logger.error('WSEndPoint', 'problem with request: ' + er.message);
					//pass the error message
                    callback(er);

				});

				wsRequest.write(message.body);
				wsRequest.end();

		}
}
<|endoftext|>


<commit_before>/*!
 * body-parser
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var bytes = require('bytes')
var deprecate = require('depd')('body-parser')
var read = require('../read')
var typer = require('media-typer')
var typeis = require('type-is')

/**
 * Module exports.
 */

module.exports = urlencoded

/**
 * Cache of parser modules.
 */

var parsers = Object.create(null)

/**
 * Create a middleware to parse urlencoded bodies.
 *
 * @param {object} [options]
 * @return {function}
 * @api public
 */

function urlencoded(options){
  options = options || {};

  // notice because option default will flip in next major
  if (options.extended === undefined) {
    deprecate('urlencoded: explicitly specify "extended: true" for extended parsing')
  }

  var extended = options.extended !== false
  var inflate = options.inflate !== false
  var limit = typeof options.limit !== 'number'
    ? bytes(options.limit || '100kb')
    : options.limit
  var type = options.type || 'urlencoded'
  var verify = options.verify || false

  if (verify !== false && typeof verify !== 'function') {
    throw new TypeError('option verify must be function')
  }

  var queryparse = extended
    ? parser('qs')
    : parser('querystring')

  function parse(body) {
    return body.length
      ? queryparse(body)
      : {}
  }

  return function urlencodedParser(req, res, next) {
    if (req._body) return next();
    req.body = req.body || {}

    if (!typeis(req, type)) return next();

    var charset = typer.parse(req).parameters.charset || 'utf-8'
    if (charset.toLowerCase() !== 'utf-8') {
      var err = new Error('unsupported charset')
      err.status = 415
      next(err)
      return
    }

    // read
    read(req, res, next, parse, {
      encoding: charset,
      inflate: inflate,
      limit: limit,
      verify: verify
    })
  }
}

/**
 * Get parser for module name dynamically.
 *
 * @param {string} name
 * @return {function}
 * @api private
 */

function parser(name) {
  var mod = parsers[name]

  if (mod) {
    return mod.parse
  }

  // load module
  mod = parsers[name] = require(name)

  return mod.parse
}
<commit_msg>Tweak extended deprecation message<commit_after>/*!
 * body-parser
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var bytes = require('bytes')
var deprecate = require('depd')('body-parser')
var read = require('../read')
var typer = require('media-typer')
var typeis = require('type-is')

/**
 * Module exports.
 */

module.exports = urlencoded

/**
 * Cache of parser modules.
 */

var parsers = Object.create(null)

/**
 * Create a middleware to parse urlencoded bodies.
 *
 * @param {object} [options]
 * @return {function}
 * @api public
 */

function urlencoded(options){
  options = options || {};

  // notice because option default will flip in next major
  if (options.extended === undefined) {
    deprecate('undefined extended: provide extended option')
  }

  var extended = options.extended !== false
  var inflate = options.inflate !== false
  var limit = typeof options.limit !== 'number'
    ? bytes(options.limit || '100kb')
    : options.limit
  var type = options.type || 'urlencoded'
  var verify = options.verify || false

  if (verify !== false && typeof verify !== 'function') {
    throw new TypeError('option verify must be function')
  }

  var queryparse = extended
    ? parser('qs')
    : parser('querystring')

  function parse(body) {
    return body.length
      ? queryparse(body)
      : {}
  }

  return function urlencodedParser(req, res, next) {
    if (req._body) return next();
    req.body = req.body || {}

    if (!typeis(req, type)) return next();

    var charset = typer.parse(req).parameters.charset || 'utf-8'
    if (charset.toLowerCase() !== 'utf-8') {
      var err = new Error('unsupported charset')
      err.status = 415
      next(err)
      return
    }

    // read
    read(req, res, next, parse, {
      encoding: charset,
      inflate: inflate,
      limit: limit,
      verify: verify
    })
  }
}

/**
 * Get parser for module name dynamically.
 *
 * @param {string} name
 * @return {function}
 * @api private
 */

function parser(name) {
  var mod = parsers[name]

  if (mod) {
    return mod.parse
  }

  // load module
  mod = parsers[name] = require(name)

  return mod.parse
}
<|endoftext|>


<commit_before>var iconv = require('iconv-lite');

var Decoder = require('../utils').Decoder;

var RE_CHARSET = /^charset$/i;

UrlEncoded.detect = /^application\/x-www-form-urlencoded$/i;
function UrlEncoded(boy, limits, headers, parsedConType) {
  this.boy = boy;

  this.fieldSizeLimit = (limits && limits.fieldSize !== undefined
                         ? limits.fieldSize
                         : 1 * 1024 * 1024);
  this.fieldNameSizeLimit = (limits && limits.fieldNameSize !== undefined
                             ? limits.fieldNameSize
                             : 100);
  this.fieldsLimit = (limits && limits.fields !== undefined
                      ? limits.fields
                      : Infinity);

  var charset;
  for (var i = 0, len = parsedConType.length; i < len; ++i) {
    if (RE_CHARSET.test(parsedConType[i][0])) {
      charset = parsedConType[i][1].toLowerCase();
      break;
    }
  }

  if (charset === undefined)
    charset = 'ISO-8859-1';
  else if (charset === 'us-ascii')
    charset = 'ascii';
  else if (charset === 'utf-8')
    charset = 'utf8';
  else if (charset === 'utf-16le')
    charset = 'ucs2';

  this.decoder = new Decoder();
  this.charset = charset;
  this._fields = 0;
  this._state = 'key';
  this._checkingBytes = true;
  this._bytesKey = 0;
  this._bytesVal = 0;
  this._key = '';
  this._val = undefined;
  this._keyTrunc = false;
  this._valTrunc = false;
  this._hitlimit = false;
}

UrlEncoded.prototype.write = function(data) {
  if (this._fields === this.fieldsLimit)
    return;

  var idxeq, idxamp, i, p = 0, len = data.length;

  while (p < len) {
    if (this._state === 'key') {
      idxeq = idxamp = undefined;
      for (i = p; i < len; ++i) {
        if (!this._checkingBytes)
          ++p;
        if (data[i] === 0x3D/*=*/) {
          idxeq = i;
          break;
        } else if (data[i] === 0x26/*&*/) {
          idxamp = i;
          break;
        }
        if (this._checkingBytes && this._bytesKey === this.fieldNameSizeLimit) {
          this._hitLimit = true;
          break;
        } else if (this._checkingBytes)
          ++this._bytesKey;
      }

      if (idxeq !== undefined) {
        // key with assignment
        if (idxeq > p)
          this._key += this.decoder.write(data.toString('binary', p, idxeq));
        this._state = 'val';

        this._hitLimit = false;
        this._checkingBytes = true;
        this._val = undefined;
        this._bytesVal = 0;
        this._valTrunc = false;
        this.decoder.reset();

        p = idxeq + 1;
      } else if (idxamp !== undefined) {
        // key with no assignment
        ++this._fields;
        var key, keyTrunc = this._keyTrunc;
        if (idxamp > p)
          key = (this._key += this.decoder.write(data.toString('binary', p, idxamp)));
        else
          key = this._key;

        this._hitLimit = false;
        this._checkingBytes = true;
        this._key = '';
        this._bytesKey = 0;
        this._keyTrunc = false;
        this.decoder.reset();

        if (key.length) {
          this.boy.emit('field', iconv.decode(
                                   new Buffer(key, 'binary'),
                                   this.charset),
                                 undefined,
                                 false,
                                 keyTrunc);
        }

        p = idxamp + 1;
        if (this._fields === this.fieldsLimit)
          return;
      } else if (this._hitLimit) {
        // we may not have hit the actual limit if there are encoded bytes...
        if (i > p)
          this._key += this.decoder.write(data.toString('binary', p, i));
        p = i;
        if ((this._bytesKey = this._key.length) === this.fieldNameSizeLimit) {
          // yep, we actually did hit the limit
          this._checkingBytes = false;
          this._keyTrunc = true;
        }
      } else {
        if (p < len)
          this._key += this.decoder.write(data.toString('binary', p));
        p = len;
      }
    } else {
      idxamp = undefined;
      for (i = p; i < len; ++i) {
        if (!this._checkingBytes)
          ++p;
        if (data[i] === 0x26/*&*/) {
          idxamp = i;
          break;
        }
        if (this._checkingBytes && this._bytesVal === this.fieldSizeLimit) {
          this._hitLimit = true;
          break;
        }
        else if (this._checkingBytes)
          ++this._bytesVal;
      }

      if (idxamp !== undefined) {
        ++this._fields;
        if (idxamp > p) {
          if (this._val === undefined)
            this._val = this.decoder.write(data.toString('binary', p, idxamp));
          else
            this._val += this.decoder.write(data.toString('binary', p, idxamp));
        }
        this.boy.emit('field', iconv.decode(
                                 new Buffer(this._key, 'binary'),
                                 this.charset),
                               (this._val
                                ? iconv.decode(
                                    new Buffer(this._val, 'binary'),
                                    this.charset)
                                : this._val),
                               this._valTrunc,
                               this._keyTrunc);
        this._state = 'key';

        this._hitLimit = false;
        this._checkingBytes = true;
        this._key = '';
        this._bytesKey = 0;
        this._keyTrunc = false;
        this.decoder.reset();

        p = idxamp + 1;
        if (this._fields === this.fieldsLimit)
          return;
      } else if (this._hitLimit) {
        // we may not have hit the actual limit if there are encoded bytes...
        if (i > p) {
          if (this._val === undefined)
            this._val = this.decoder.write(data.toString('binary', p, i));
          else
            this._val += this.decoder.write(data.toString('binary', p, i));
        }
        p = i;
        if ((this._val === undefined && this.fieldSizeLimit === 0)
            || (this._bytesVal = this._val.length) === this.fieldSizeLimit) {
          // yep, we actually did hit the limit
          this._checkingBytes = false;
          this._valTrunc = true;
        }
      } else {
        if (p < len) {
          if (this._val === undefined)
            this._val = this.decoder.write(data.toString('binary', p));
          else
            this._val += this.decoder.write(data.toString('binary', p));
        }
        p = len;
      }
    }
  }
};

UrlEncoded.prototype.end = function() {
  if (this._state === 'key' && this._key.length > 0) {
    this.boy.emit('field', iconv.decode(
                             new Buffer(this._key, 'binary'),
                             this.charset),
                           undefined,
                           false,
                           this._keyTrunc);
  } else if (this._state === 'val') {
    this.boy.emit('field', iconv.decode(
                             new Buffer(this._key, 'binary'),
                             this.charset),
                           (this._val
                            ? iconv.decode(
                                new Buffer(this._val, 'binary'),
                                this.charset)
                            : this._val),
                           this._valTrunc,
                           this._keyTrunc);
  }
  this.boy.emit('end');
};

module.exports = UrlEncoded;
<commit_msg>urlencoded: remove iconv-lite usage<commit_after>var jsencoding = require('../../deps/encoding/encoding'),
    Decoder = require('../utils').Decoder;

var RE_CHARSET = /^charset$/i;

UrlEncoded.detect = /^application\/x-www-form-urlencoded$/i;
function UrlEncoded(boy, limits, headers, parsedConType) {
  this.boy = boy;

  this.fieldSizeLimit = (limits && limits.fieldSize !== undefined
                         ? limits.fieldSize
                         : 1 * 1024 * 1024);
  this.fieldNameSizeLimit = (limits && limits.fieldNameSize !== undefined
                             ? limits.fieldNameSize
                             : 100);
  this.fieldsLimit = (limits && limits.fields !== undefined
                      ? limits.fields
                      : Infinity);

  var charset;
  for (var i = 0, len = parsedConType.length; i < len; ++i) {
    if (RE_CHARSET.test(parsedConType[i][0])) {
      charset = parsedConType[i][1].toLowerCase();
      break;
    }
  }

  if (charset === undefined)
    charset = 'ISO-8859-1';

  this.decoder = new Decoder();
  this.charset = charset;
  this._fields = 0;
  this._state = 'key';
  this._checkingBytes = true;
  this._bytesKey = 0;
  this._bytesVal = 0;
  this._key = '';
  this._val = undefined;
  this._keyTrunc = false;
  this._valTrunc = false;
  this._hitlimit = false;
}

UrlEncoded.prototype.write = function(data) {
  if (this._fields === this.fieldsLimit)
    return;

  var idxeq, idxamp, i, p = 0, len = data.length;

  while (p < len) {
    if (this._state === 'key') {
      idxeq = idxamp = undefined;
      for (i = p; i < len; ++i) {
        if (!this._checkingBytes)
          ++p;
        if (data[i] === 0x3D/*=*/) {
          idxeq = i;
          break;
        } else if (data[i] === 0x26/*&*/) {
          idxamp = i;
          break;
        }
        if (this._checkingBytes && this._bytesKey === this.fieldNameSizeLimit) {
          this._hitLimit = true;
          break;
        } else if (this._checkingBytes)
          ++this._bytesKey;
      }

      if (idxeq !== undefined) {
        // key with assignment
        if (idxeq > p)
          this._key += this.decoder.write(data.toString('binary', p, idxeq));
        this._state = 'val';

        this._hitLimit = false;
        this._checkingBytes = true;
        this._val = undefined;
        this._bytesVal = 0;
        this._valTrunc = false;
        this.decoder.reset();

        p = idxeq + 1;
      } else if (idxamp !== undefined) {
        // key with no assignment
        ++this._fields;
        var key, keyTrunc = this._keyTrunc;
        if (idxamp > p)
          key = (this._key += this.decoder.write(data.toString('binary', p, idxamp)));
        else
          key = this._key;

        this._hitLimit = false;
        this._checkingBytes = true;
        this._key = '';
        this._bytesKey = 0;
        this._keyTrunc = false;
        this.decoder.reset();

        if (key.length) {
          this.boy.emit('field', convertVal(buffer, this.charset),
                                 undefined,
                                 false,
                                 keyTrunc);
        }

        p = idxamp + 1;
        if (this._fields === this.fieldsLimit)
          return;
      } else if (this._hitLimit) {
        // we may not have hit the actual limit if there are encoded bytes...
        if (i > p)
          this._key += this.decoder.write(data.toString('binary', p, i));
        p = i;
        if ((this._bytesKey = this._key.length) === this.fieldNameSizeLimit) {
          // yep, we actually did hit the limit
          this._checkingBytes = false;
          this._keyTrunc = true;
        }
      } else {
        if (p < len)
          this._key += this.decoder.write(data.toString('binary', p));
        p = len;
      }
    } else {
      idxamp = undefined;
      for (i = p; i < len; ++i) {
        if (!this._checkingBytes)
          ++p;
        if (data[i] === 0x26/*&*/) {
          idxamp = i;
          break;
        }
        if (this._checkingBytes && this._bytesVal === this.fieldSizeLimit) {
          this._hitLimit = true;
          break;
        }
        else if (this._checkingBytes)
          ++this._bytesVal;
      }

      if (idxamp !== undefined) {
        ++this._fields;
        if (idxamp > p) {
          if (this._val === undefined)
            this._val = this.decoder.write(data.toString('binary', p, idxamp));
          else
            this._val += this.decoder.write(data.toString('binary', p, idxamp));
        }
        this.boy.emit('field', convertVal(this._key, this.charset),
                               convertVal(this._val, this.charset),
                               this._valTrunc,
                               this._keyTrunc);
        this._state = 'key';

        this._hitLimit = false;
        this._checkingBytes = true;
        this._key = '';
        this._bytesKey = 0;
        this._keyTrunc = false;
        this.decoder.reset();

        p = idxamp + 1;
        if (this._fields === this.fieldsLimit)
          return;
      } else if (this._hitLimit) {
        // we may not have hit the actual limit if there are encoded bytes...
        if (i > p) {
          if (this._val === undefined)
            this._val = this.decoder.write(data.toString('binary', p, i));
          else
            this._val += this.decoder.write(data.toString('binary', p, i));
        }
        p = i;
        if ((this._val === undefined && this.fieldSizeLimit === 0)
            || (this._bytesVal = this._val.length) === this.fieldSizeLimit) {
          // yep, we actually did hit the limit
          this._checkingBytes = false;
          this._valTrunc = true;
        }
      } else {
        if (p < len) {
          if (this._val === undefined)
            this._val = this.decoder.write(data.toString('binary', p));
          else
            this._val += this.decoder.write(data.toString('binary', p));
        }
        p = len;
      }
    }
  }
};

UrlEncoded.prototype.end = function() {
  if (this._state === 'key' && this._key.length > 0) {
    this.boy.emit('field', convertVal(this._key, this.charset),
                           undefined,
                           false,
                           this._keyTrunc);
  } else if (this._state === 'val') {
    this.boy.emit('field', convertVal(this._key, this.charset),
                           convertVal(this._val, this.charset),
                           this._valTrunc,
                           this._keyTrunc);
  }
  this.boy.emit('end');
};

function convertVal(val, charset) {
  var ret = val;
  if (val && val.length && jsencoding.encodingExists(charset)) {
    try {
      ret = jsencoding.TextDecoder(charset)
                      .decode(new Buffer(val, 'binary'));
    } catch(e) {}
  }
  return ret;
}

module.exports = UrlEncoded;
<|endoftext|>


<commit_before>
var pagination = require('sr-pagination');
var query = require('./query');

exports = module.exports = function (args, cb) {
    var str = query.replace('total', args.config.table.name);
    args.db.client.query(str, function (err, rows) {
        if (err) return cb(err);
        var total = parseInt(rows[0].count),
            rows = args.config.listview.page,
            page = parseInt(args.page || 1);
        cb(null, pagination({page: page, links: 9, rows: rows, total: total}));
    });
}
<commit_msg>Filter out the total records count<commit_after>
var pagination = require('sr-pagination');
var query = require('./query'),
    sql = require('./sql');

exports.get = function (args, cb) {
    var s = args.statements,
        pk = sql.fullName(args.config.table.name, args.config.table.pk);

    var str = query.replace('total', pk, s.table, s.join, s.where);
    args.db.client.query(str, function (err, rows) {
        if (err) return cb(err);
        var total = parseInt(rows[0].count),
            rows = args.config.listview.page,
            page = parseInt(args.page || 1);
        cb(null, pagination({page: page, links: 9, rows: rows, total: total}));
    });
}
<|endoftext|>


<commit_before>/*!
 * qwebs
 * Copyright(c) 2015 Benoît Claveau <benoit.claveau@gmail.com>
 * MIT Licensed
 */

"use strict";

const path = require("path");
const walk = require("./../utils/walk.js");
const fs = require("fs");
const DataError = require("./../dataerror");

class Repository {
    constructor(folder) {
        if (!folder) throw new DataError({ message: "Folder is not defined.", data: { folder: folder }});

        let files = walk.get(folder);
        for (let i in files) {
            let filepath = files[i];

            let route = filepath.substring(folder.length);
            let ext = path.extname(route).substr(1); //get extension without .
            route = route.slice(0, -(ext.length + 1)); //get file name withous extension and .
            let routes = route.split("/");

            let data = this;
            for (let j in routes) {
                let token = routes[j];
                if(!token) continue; //if filepath start with /
                data[token] = data[token] || {};
                data = data[token];
            }

            //TODO change encoding according to the extension
            if(data[ext]) throw new DataError({ message: "File already exists.", date: { file: filepath }});
            this.readFile(filepath, ext).then(content => {
                data[ext] = content;
            }).catch(error => {
                throw new DataError({ message: error.message, stack: error.stack });
            });
        };
    };

    readFile(filepath, ext) {
        return new Promise((resolve, reject) => {
            fs.readFile(filepath, "utf8", (err, data) => {
                if (err) reject(err);
                else resolve(data);
            });
        });
    };
};

exports = module.exports = Repository;<commit_msg>Move promise to function in repository.js<commit_after>/*!
 * qwebs
 * Copyright(c) 2015 Benoît Claveau <benoit.claveau@gmail.com>
 * MIT Licensed
 */

"use strict";

const path = require("path");
const walk = require("./../utils/walk.js");
const fs = require("fs");
const DataError = require("./../dataerror");

class Repository {
    constructor(folder) {
        if (!folder) throw new DataError({ message: "Folder is not defined.", data: { folder: folder }});
        this.folder = folder;
    }

    load() {
        return new Promise.resolve().then(() => {
            let promises = []
            let files = walk.get(this.folder);
            for (filepath of files) {
                let route = filepath.substring(this.folder.length);
                let ext = path.extname(route).substr(1); //get extension without .
                route = route.slice(0, -(ext.length + 1)); //get file name withous extension and .
                let routes = route.split("/");

                let data = this;
                for (token of routes) {
                    if(!token) continue; //if filepath start with /
                    data[token] = data[token] || {};
                    data = data[token];
                }

                //TODO change encoding according to the extension
                if(data[ext]) throw new DataError({ message: "File already exists.", date: { file: filepath }});

                let promise = this.readFile(filepath, ext).then(content => {
                    data[ext] = content;
                }).catch(error => {
                    throw new DataError({ message: error.message, stack: error.stack });
                });

                promises.push(promise);
            };

            return Promise.all(promises);
        });
    };

    readFile(filepath, ext) {
        return new Promise((resolve, reject) => {
            fs.readFile(filepath, "utf8", (err, data) => {
                if (err) reject(err);
                else resolve(data);
            });
        });
    };
};

exports = module.exports = Repository;<|endoftext|>


<commit_before>
module.exports = writeShim
writeShim.ifExists = shimIfExists

var fs = require("./graceful-fs")
  , path = require("path")
  , relativize = require("./relativize")
  , mkdir = require("./mkdir-p")
  , log = require("./log")

function shimIfExists (from, to, dep, cb) {
  if (!cb) cb = dep, dep = false
  fs.stat(from, function (er) {
    if (er) return cb()
    writeShim(from, to, dep, cb)
  })
}

function writeShim (from, to, dep, cb) {
  if (!cb) cb = dep, dep = false
  log.silly([from,to], "writeShim")
  if (dep) dep = relativize(dep, to)
  from = relativize(from, to).replace(/\.(js|node)$/, '')
  var nodePath = process.execPath
               || path.join(process.installPrefix, "bin", "node")
    , code = "#!"+nodePath+"\n"
           + "// generated by npm, please don't touch!\n"
           + (dep ? "var dep = require('path').join(__dirname, "
                  + JSON.stringify(dep || null) + ")\n"
                  + "var depMet = require.paths.indexOf(dep) !== -1\n"
                  : "")
           + "var from = "+JSON.stringify(from)+"\n"
           + "\n"
           + (dep ? "if (!depMet) require.paths.unshift(dep)\n" : "")
           + "module.exports = require(from)\n"
           + "\n"
           + (dep ? "if (!depMet) {\n"
                  + "  var i = require.paths.indexOf(dep)\n"
                  + "  if (i !== -1) require.paths.splice(i, 1)\n"
                  + "}\n"
                  : "")

  mkdir(path.dirname(to), function (er) {
    if (er) return cb(er)
    fs.writeFile(to, code, "ascii", function (er, ok) {
      if (er) return cb(er)
      fs.chmod(to, 0755, cb)
    })
  })
}
<commit_msg>ask the env where node is, don't hard-code it.<commit_after>
module.exports = writeShim
writeShim.ifExists = shimIfExists

var fs = require("./graceful-fs")
  , path = require("path")
  , relativize = require("./relativize")
  , mkdir = require("./mkdir-p")
  , log = require("./log")

function shimIfExists (from, to, dep, cb) {
  if (!cb) cb = dep, dep = false
  fs.stat(from, function (er) {
    if (er) return cb()
    writeShim(from, to, dep, cb)
  })
}

function writeShim (from, to, dep, cb) {
  if (!cb) cb = dep, dep = false
  log.silly([from,to], "writeShim")
  if (dep) dep = relativize(dep, to)
  from = relativize(from, to).replace(/\.(js|node)$/, '')
  // todo: remove this dep juggling when 0.2.x is deprecated,
  // and node_modules is picked up automatically.2
  var code = "#!/usr/bin/env node\n"
           + "// generated by npm, please don't touch!\n"
           + (dep ? "var dep = require('path').join(__dirname, "
                  + JSON.stringify(dep || null) + ")\n"
                  + "var depMet = require.paths.indexOf(dep) !== -1\n"
                  : "")
           + "var from = "+JSON.stringify(from)+"\n"
           + "\n"
           + (dep ? "if (!depMet) require.paths.unshift(dep)\n" : "")
           + "module.exports = require(from)\n"
           + "\n"
           + (dep ? "if (!depMet) {\n"
                  + "  var i = require.paths.indexOf(dep)\n"
                  + "  if (i !== -1) require.paths.splice(i, 1)\n"
                  + "}\n"
                  : "")

  mkdir(path.dirname(to), function (er) {
    if (er) return cb(er)
    fs.writeFile(to, code, "ascii", function (er, ok) {
      if (er) return cb(er)
      fs.chmod(to, 0755, cb)
    })
  })
}
<|endoftext|>


<commit_before>import extend from 'extend';
import Parchment from 'parchment';
import Quill from '../core/quill';
import logger from '../core/logger';
import Module from '../core/module';

let debug = logger('quill:toolbar');

class Toolbar extends Module {
  constructor(quill, options) {
    options.handlers = extend({}, Toolbar.DEFAULTS.handlers, options.handlers);
    super(quill, options);
    if (typeof this.options.container === 'string') {
      this.container = document.querySelector(this.options.container);
    } else if (Array.isArray(this.options.container)) {
      let container = document.createElement('div');
      addControls(container, this.options.container);
      quill.container.parentNode.insertBefore(container, quill.container);
      this.container = container;
    } else {
      this.container = this.options.container;
    }
    if (!(this.container instanceof HTMLElement)) {
      return debug.error('Container required for toolbar', this.options);
    }
    this.container.classList.add('ql-toolbar');
    this.controls = [];
    this.handlers = {};
    Object.keys(this.options.handlers).forEach((format) => {
      this.addHandler(format, this.options.handlers[format]);
    });
    [].forEach.call(this.container.querySelectorAll('button, select'), (input) => {
      this.attach(input);
    });
    this.quill.on(Quill.events.SELECTION_CHANGE, this.update, this);
    this.quill.on(Quill.events.SCROLL_OPTIMIZE, () => {
      let [range, ] = this.quill.selection.getRange();  // quill.getSelection triggers update
      this.update(range);
    });
  }

  addHandler(format, handler) {
    this.handlers[format] = handler;
  }

  attach(input) {
    let format = [].find.call(input.classList, (className) => {
      return className.indexOf('ql-') === 0;
    });
    if (!format) return;
    format = format.slice('ql-'.length);
    if (this.handlers[format] == null) {
      if (this.quill.scroll.whitelist != null && this.quill.scroll.whitelist[format] == null) {
        debug.warn('ignoring attaching to disabled format', format, input);
        return;
      }
      if (Parchment.query(format) == null) {
        debug.warn('ignoring attaching to nonexistent format', format, input);
        return;
      }
    }
    let eventNames = input.tagName === 'SELECT' ? ['change'] : ['mousedown', 'touchstart'];
    eventNames.forEach((eventName) => {
      input.addEventListener(eventName, (e) => {
        let value;
        if (input.tagName === 'SELECT') {
          if (input.selectedIndex < 0) return;
          let selected = input.options[input.selectedIndex];
          if (selected.hasAttribute('selected')) {
            value = false;
          } else {
            value = selected.value || false;
          }
        } else {
          value = input.classList.contains('ql-active') ? false : input.value || true;
          e.preventDefault();
        }
        this.quill.focus();
        if (this.handlers[format] != null) {
          this.handlers[format].call(this, value);
        } else {
          this.quill.format(format, value, Quill.sources.USER);
        }
        let [range, ] = this.quill.selection.getRange();
        this.update(range);
      });
    });
    // TODO use weakmap
    this.controls.push([format, input]);
  }

  update(range) {
    if (range == null) return;
    let formats = this.quill.getFormat(range);
    this.controls.forEach(function(pair) {
      let [format, input] = pair;
      if (input.tagName === 'SELECT') {
        let option;
        if (formats[format] == null) {
          option = input.querySelector('option[selected]');
        } else if (!Array.isArray(formats[format])) {
          option = input.querySelector(`option[value="${formats[format]}"]`);
        }
        if (option == null) {
          input.value = '';   // TODO make configurable?
          input.selectedIndex = -1;
        } else {
          option.selected = true;
        }
      } if (input.value) {
        let active = input.value === formats[format] ||
                     (formats[format] != null && input.value === formats[format].toString());
        input.classList.toggle('ql-active', active);
      } else {
        input.classList.toggle('ql-active', formats[format] || false);
      }
    });
  }
}
Toolbar.DEFAULTS = {};

function addButton(container, format, value) {
  let input = document.createElement('button');
  input.setAttribute('type', 'button');
  input.classList.add('ql-' + format);
  if (value != null) {
    input.value = value;
  }
  container.appendChild(input);
}

function addControls(container, groups) {
  if (!Array.isArray(groups[0])) {
    groups = [groups];
  }
  groups.forEach(function(controls) {
    let group = document.createElement('span');
    group.classList.add('ql-formats');
    controls.forEach(function(control) {
      if (typeof control === 'string') {
        addButton(group, control);
      } else {
        let format = Object.keys(control)[0];
        let value = control[format];
        if (Array.isArray(value)) {
          addSelect(group, format, value);
        } else {
          addButton(group, format, value);
        }
      }
    });
    container.appendChild(group);
  });
}

function addSelect(container, format, values) {
  let input = document.createElement('select');
  input.classList.add('ql-' + format);
  values.forEach(function(value) {
    let option = document.createElement('option');
    if (value !== false) {
      option.setAttribute('value', value);
    } else {
      option.setAttribute('selected', 'selected');
    }
    input.appendChild(option);
  });
  container.appendChild(input);
}

Toolbar.DEFAULTS = {
  container: null,
  handlers: {
    clean: function(value) {
      let range = this.quill.getSelection();
      if (range == null) return;
      if (range.length == 0) {
        let formats = this.quill.getFormat();
        Object.keys(formats).forEach((name) => {
          if (Parchment.query(name, Parchment.Scope.INLINE) != null) {
            this.quill.format(name, false);
          }
        });
      } else {
        let startLength = this.quill.getLength();
        this.quill.removeFormat(range, Quill.sources.USER);
        let endLength = this.quill.getLength();
        // account for embed removals
        this.quill.setSelection(range.index, range.length - (startLength-endLength), Quill.sources.SILENT);
      }
    },
    direction: function(value) {
      let align = this.quill.getFormat()['align'];
      if (value === 'rtl' && align == null) {
        this.quill.format('align', 'right', Quill.sources.USER);
      } else if (!value && align === 'right') {
        this.quill.format('align', false, Quill.sources.USER);
      }
      this.quill.format('direction', value, Quill.sources.USER);
    },
    indent: function(value) {
      let range = this.quill.getSelection();
      let formats = this.quill.getFormat(range);
      let indent = parseInt(formats.indent || 0);
      if (value === '+1') {
        this.quill.format('indent', indent + 1, Quill.sources.USER);
      } else if (value === '-1') {
        this.quill.format('indent', indent - 1, Quill.sources.USER);
      }
    }
  }
}

export { Toolbar as default, addControls };
<commit_msg>closes #733<commit_after>import extend from 'extend';
import Parchment from 'parchment';
import Quill from '../core/quill';
import logger from '../core/logger';
import Module from '../core/module';

let debug = logger('quill:toolbar');

class Toolbar extends Module {
  constructor(quill, options) {
    options.handlers = extend({}, Toolbar.DEFAULTS.handlers, options.handlers);
    super(quill, options);
    if (typeof this.options.container === 'string') {
      this.container = document.querySelector(this.options.container);
    } else if (Array.isArray(this.options.container)) {
      let container = document.createElement('div');
      addControls(container, this.options.container);
      quill.container.parentNode.insertBefore(container, quill.container);
      this.container = container;
    } else {
      this.container = this.options.container;
    }
    if (!(this.container instanceof HTMLElement)) {
      return debug.error('Container required for toolbar', this.options);
    }
    this.container.classList.add('ql-toolbar');
    this.controls = [];
    this.handlers = {};
    Object.keys(this.options.handlers).forEach((format) => {
      this.addHandler(format, this.options.handlers[format]);
    });
    [].forEach.call(this.container.querySelectorAll('button, select'), (input) => {
      this.attach(input);
    });
    this.quill.on(Quill.events.SELECTION_CHANGE, this.update, this);
    this.quill.on(Quill.events.SCROLL_OPTIMIZE, () => {
      let [range, ] = this.quill.selection.getRange();  // quill.getSelection triggers update
      this.update(range);
    });
  }

  addHandler(format, handler) {
    this.handlers[format] = handler;
  }

  attach(input) {
    let format = [].find.call(input.classList, (className) => {
      return className.indexOf('ql-') === 0;
    });
    if (!format) return;
    format = format.slice('ql-'.length);
    if (input.tagName === 'BUTTON') {
      input.setAttribute('type', 'button');
    }
    if (this.handlers[format] == null) {
      if (this.quill.scroll.whitelist != null && this.quill.scroll.whitelist[format] == null) {
        debug.warn('ignoring attaching to disabled format', format, input);
        return;
      }
      if (Parchment.query(format) == null) {
        debug.warn('ignoring attaching to nonexistent format', format, input);
        return;
      }
    }
    let eventNames = input.tagName === 'SELECT' ? ['change'] : ['mousedown', 'touchstart'];
    eventNames.forEach((eventName) => {
      input.addEventListener(eventName, (e) => {
        let value;
        if (input.tagName === 'SELECT') {
          if (input.selectedIndex < 0) return;
          let selected = input.options[input.selectedIndex];
          if (selected.hasAttribute('selected')) {
            value = false;
          } else {
            value = selected.value || false;
          }
        } else {
          value = input.classList.contains('ql-active') ? false : input.value || true;
          e.preventDefault();
        }
        this.quill.focus();
        if (this.handlers[format] != null) {
          this.handlers[format].call(this, value);
        } else {
          this.quill.format(format, value, Quill.sources.USER);
        }
        let [range, ] = this.quill.selection.getRange();
        this.update(range);
      });
    });
    // TODO use weakmap
    this.controls.push([format, input]);
  }

  update(range) {
    if (range == null) return;
    let formats = this.quill.getFormat(range);
    this.controls.forEach(function(pair) {
      let [format, input] = pair;
      if (input.tagName === 'SELECT') {
        let option;
        if (formats[format] == null) {
          option = input.querySelector('option[selected]');
        } else if (!Array.isArray(formats[format])) {
          option = input.querySelector(`option[value="${formats[format]}"]`);
        }
        if (option == null) {
          input.value = '';   // TODO make configurable?
          input.selectedIndex = -1;
        } else {
          option.selected = true;
        }
      } if (input.value) {
        let active = input.value === formats[format] ||
                     (formats[format] != null && input.value === formats[format].toString());
        input.classList.toggle('ql-active', active);
      } else {
        input.classList.toggle('ql-active', formats[format] || false);
      }
    });
  }
}
Toolbar.DEFAULTS = {};

function addButton(container, format, value) {
  let input = document.createElement('button');
  input.setAttribute('type', 'button');
  input.classList.add('ql-' + format);
  if (value != null) {
    input.value = value;
  }
  container.appendChild(input);
}

function addControls(container, groups) {
  if (!Array.isArray(groups[0])) {
    groups = [groups];
  }
  groups.forEach(function(controls) {
    let group = document.createElement('span');
    group.classList.add('ql-formats');
    controls.forEach(function(control) {
      if (typeof control === 'string') {
        addButton(group, control);
      } else {
        let format = Object.keys(control)[0];
        let value = control[format];
        if (Array.isArray(value)) {
          addSelect(group, format, value);
        } else {
          addButton(group, format, value);
        }
      }
    });
    container.appendChild(group);
  });
}

function addSelect(container, format, values) {
  let input = document.createElement('select');
  input.classList.add('ql-' + format);
  values.forEach(function(value) {
    let option = document.createElement('option');
    if (value !== false) {
      option.setAttribute('value', value);
    } else {
      option.setAttribute('selected', 'selected');
    }
    input.appendChild(option);
  });
  container.appendChild(input);
}

Toolbar.DEFAULTS = {
  container: null,
  handlers: {
    clean: function(value) {
      let range = this.quill.getSelection();
      if (range == null) return;
      if (range.length == 0) {
        let formats = this.quill.getFormat();
        Object.keys(formats).forEach((name) => {
          if (Parchment.query(name, Parchment.Scope.INLINE) != null) {
            this.quill.format(name, false);
          }
        });
      } else {
        let startLength = this.quill.getLength();
        this.quill.removeFormat(range, Quill.sources.USER);
        let endLength = this.quill.getLength();
        // account for embed removals
        this.quill.setSelection(range.index, range.length - (startLength-endLength), Quill.sources.SILENT);
      }
    },
    direction: function(value) {
      let align = this.quill.getFormat()['align'];
      if (value === 'rtl' && align == null) {
        this.quill.format('align', 'right', Quill.sources.USER);
      } else if (!value && align === 'right') {
        this.quill.format('align', false, Quill.sources.USER);
      }
      this.quill.format('direction', value, Quill.sources.USER);
    },
    indent: function(value) {
      let range = this.quill.getSelection();
      let formats = this.quill.getFormat(range);
      let indent = parseInt(formats.indent || 0);
      if (value === '+1') {
        this.quill.format('indent', indent + 1, Quill.sources.USER);
      } else if (value === '-1') {
        this.quill.format('indent', indent - 1, Quill.sources.USER);
      }
    }
  }
}

export { Toolbar as default, addControls };
<|endoftext|>


<commit_before>import {
    event as d3_event,
    select as d3_select,
    selectAll as d3_selectAll
} from 'd3-selection';

import { t, textDirection } from '../util/locale';
import { tooltip } from '../util/tooltip';

import { behaviorHash } from '../behavior';
import { modeBrowse } from '../modes/browse';
import { svgDefs, svgIcon } from '../svg';
import { utilGetDimensions } from '../util/dimensions';

import { uiAccount } from './account';
import { uiAttribution } from './attribution';
import { uiBackground } from './background';
import { uiContributors } from './contributors';
import { uiFeatureInfo } from './feature_info';
import { uiFullScreen } from './full_screen';
import { uiGeolocate } from './geolocate';
import { uiHelp } from './help';
import { uiInfo } from './info';
import { uiIntro } from './intro';
import { uiIssues } from './issues';
import { uiLoading } from './loading';
import { uiMapData } from './map_data';
import { uiMapInMap } from './map_in_map';
import { uiNotice } from './notice';
import { uiPhotoviewer } from './photoviewer';
import { uiRestore } from './restore';
import { uiScale } from './scale';
import { uiShortcuts } from './shortcuts';
import { uiSidebar } from './sidebar';
import { uiSpinner } from './spinner';
import { uiSplash } from './splash';
import { uiStatus } from './status';
import { uiTopToolbar } from './top_toolbar';
import { uiVersion } from './version';
import { uiZoom } from './zoom';
import { uiCmd } from './cmd';

export function uiInit(context) {
    var _initCounter = 0;
    var _initCallback;
    var _needWidth = {};

    function render(container) {
        container
            .attr('dir', textDirection);

        // setup fullscreen keybindings (no button shown at this time)
        container
            .call(uiFullScreen(context));

        var map = context.map();

        container
            .append('svg')
            .attr('id', 'defs')
            .call(svgDefs(context));

        container
            .append('div')
            .attr('id', 'sidebar')
            .call(ui.sidebar);

        var content = container
            .append('div')
            .attr('id', 'content')
            .attr('class', 'active');

        // Top toolbar
        content
            .append('div')
            .attr('id', 'bar')
            .attr('class', 'fillD')
            .call(uiTopToolbar(context));

        content
            .append('div')
            .attr('id', 'map')
            .attr('dir', 'ltr')
            .call(map);

        // Map controls
        var controls = content
            .append('div')
            .attr('class', 'map-controls');

        controls
            .append('div')
            .attr('class', 'map-control zoombuttons')
            .call(uiZoom(context));

        controls
            .append('div')
            .attr('class', 'map-control geolocate-control')
            .call(uiGeolocate(context));

        var background = uiBackground(context);
        controls
            .append('div')
            .attr('class', 'map-control background-control')
            .call(background.renderToggleButton);

        var mapData = uiMapData(context);
        controls
            .append('div')
            .attr('class', 'map-control map-data-control')
            .call(mapData.renderToggleButton);

        var issues = uiIssues(context);
        controls
            .append('div')
            .attr('class', 'map-control map-issues-control')
            .call(issues.renderToggleButton);

        var help = uiHelp(context);
        controls
            .append('div')
            .attr('class', 'map-control help-control')
            .call(help.renderToggleButton);

        content
            .append('div')
            .attr('class', 'spinner')
            .call(uiSpinner(context));

        // Add attribution and footer
        var about = content
            .append('div')
            .attr('id', 'about');

        about
            .append('div')
            .attr('id', 'attrib')
            .attr('dir', 'ltr')
            .call(uiAttribution(context));

        about
            .append('div')
            .attr('class', 'api-status')
            .call(uiStatus(context));

        var footer = about
            .append('div')
            .attr('id', 'footer')
            .attr('class', 'fillD');

        footer
            .append('div')
            .attr('id', 'flash-wrap')
            .attr('class', 'footer-hide');

        var footerWrap = footer
            .append('div')
            .attr('id', 'footer-wrap')
            .attr('class', 'footer-show');

        footerWrap
            .append('div')
            .attr('id', 'scale-block')
            .call(uiScale(context));

        var aboutList = footerWrap
            .append('div')
            .attr('id', 'info-block')
            .append('ul')
            .attr('id', 'about-list');

        if (!context.embed()) {
            aboutList
                .call(uiAccount(context));
        }

        aboutList
            .append('li')
            .attr('class', 'version')
            .call(uiVersion(context));

        var issueLinks = aboutList
            .append('li');

        issueLinks
            .append('a')
            .attr('target', '_blank')
            .attr('tabindex', -1)
            .attr('href', 'https://github.com/openstreetmap/iD/issues')
            .call(svgIcon('#iD-icon-bug', 'light'))
            .call(tooltip().title(t('report_a_bug')).placement('top'));

        issueLinks
            .append('a')
            .attr('target', '_blank')
            .attr('tabindex', -1)
            .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
            .call(svgIcon('#iD-icon-translate', 'light'))
            .call(tooltip().title(t('help_translate')).placement('top'));

        aboutList
            .append('li')
            .attr('class', 'feature-warning')
            .attr('tabindex', -1)
            .call(uiFeatureInfo(context));

        aboutList
            .append('li')
            .attr('class', 'user-list')
            .attr('tabindex', -1)
            .call(uiContributors(context));

        // Setup map dimensions and move map to initial center/zoom.
        // This should happen after #content and toolbars exist.
        ui.onResize();

        var hash = behaviorHash(context);
        hash();
        if (!hash.hadHash) {
            map.centerZoom([0, 0], 2);
        }

        var overMap = content
            .append('div')
            .attr('class', 'over-map');

        // Add panes
        // This should happen after map is initialized, as some require surface()
        var panes = overMap
            .append('div')
            .attr('class', 'map-panes');

        panes
            .call(background.renderPane)
            .call(mapData.renderPane)
            .call(issues.renderPane)
            .call(help.renderPane);

        // Add absolutely-positioned elements that sit on top of the map
        // This should happen after the map is ready (center/zoom)
        overMap
            .call(uiMapInMap(context))
            .call(uiInfo(context))
            .call(uiNotice(context));

        overMap
            .append('div')
            .attr('id', 'photoviewer')
            .classed('al', true)       // 'al'=left,  'ar'=right
            .classed('hide', true)
            .call(ui.photoviewer);

        // Bind events
        window.onbeforeunload = function() {
            return context.save();
        };
        window.onunload = function() {
            context.history().unlock();
        };

        d3_select(window)
            .on('gesturestart.editor', eventCancel)
            .on('gesturechange.editor', eventCancel)
            .on('gestureend.editor', eventCancel)
            .on('resize.editor', ui.onResize);

        var panPixels = 80;
        context.keybinding()
            .on('⌫', function() { d3_event.preventDefault(); })
            .on([t('sidebar.key'), '`', '²'], ui.sidebar.toggle)   // #5663 - common QWERTY, AZERTY
            .on('←', pan([panPixels, 0]))
            .on('↑', pan([0, panPixels]))
            .on('→', pan([-panPixels, 0]))
            .on('↓', pan([0, -panPixels]))
            .on(['⇧←', uiCmd('⌘←')], pan([map.dimensions()[0], 0]))
            .on(['⇧↑', uiCmd('⌘↑')], pan([0, map.dimensions()[1]]))
            .on(['⇧→', uiCmd('⌘→')], pan([-map.dimensions()[0], 0]))
            .on(['⇧↓', uiCmd('⌘↓')], pan([0, -map.dimensions()[1]]));

        context.enter(modeBrowse(context));

        if (!_initCounter++) {
            if (!hash.startWalkthrough) {
                context.container()
                    .call(uiSplash(context))
                    .call(uiRestore(context));
            }

            context.container()
                .call(uiShortcuts(context));
        }

        var osm = context.connection();
        var auth = uiLoading(context).message(t('loading_auth')).blocking(true);

        if (osm && auth) {
            osm
                .on('authLoading.ui', function() {
                    context.container()
                        .call(auth);
                })
                .on('authDone.ui', function() {
                    auth.close();
                });
        }

        _initCounter++;

        if (hash.startWalkthrough) {
            hash.startWalkthrough = false;
            context.container().call(uiIntro(context));
        }

        function pan(d) {
            return function() {
                if (d3_select('.combobox').size()) return;
                d3_event.preventDefault();
                context.pan(d, 100);
            };
        }

        function eventCancel() {
            d3_event.preventDefault();
        }
    }

    function ui(node, callback) {
        _initCallback = callback;
        var container = d3_select(node);
        context.container(container);
        context.loadLocale(function(err) {
            if (!err) {
                render(container);
            }
            if (callback) {
                callback(err);
            }
        });
    }

    ui.restart = function(arg) {
        context.keybinding().clear();
        context.locale(arg);
        context.loadLocale(function(err) {
            if (!err) {
                context.container().selectAll('*').remove();
                render(context.container());
                if (_initCallback) _initCallback();
            }
        });
    };

    ui.sidebar = uiSidebar(context);

    ui.photoviewer = uiPhotoviewer(context);

    ui.onResize = function(withPan) {
        var map = context.map();

        // Recalc dimensions of map and sidebar.. (`true` = force recalc)
        // This will call `getBoundingClientRect` and trigger reflow,
        //  but the values will be cached for later use.
        var mapDimensions = utilGetDimensions(d3_select('#content'), true);
        utilGetDimensions(d3_select('#sidebar'), true);

        if (withPan !== undefined) {
            map.redrawEnable(false);
            map.pan(withPan);
            map.redrawEnable(true);
        }
        map.dimensions(mapDimensions);

        ui.photoviewer.onMapResize();

        // check if header or footer have overflowed
        ui.checkOverflow('#bar');
        ui.checkOverflow('#footer');

        // Use outdated code so it works on Explorer
        var resizeWindowEvent = document.createEvent('Event');

        resizeWindowEvent.initEvent('resizeWindow', true, true);

        document.dispatchEvent(resizeWindowEvent);
    };

    // Call checkOverflow when resizing or whenever the contents change.
    ui.checkOverflow = function(selector, reset) {
        if (reset) {
            delete _needWidth[selector];
        }

        var element = d3_select(selector);
        var scrollWidth = element.property('scrollWidth');
        var clientWidth = element.property('clientWidth');
        var needed = _needWidth[selector] || scrollWidth;

        if (scrollWidth > clientWidth) {    // overflow happening
            element.classed('narrow', true);
            if (!_needWidth[selector]) {
                _needWidth[selector] = scrollWidth;
            }

        } else if (scrollWidth >= needed) {
            element.classed('narrow', false);
        }
    };

    ui.togglePanes = function(showPane) {
        var shownPanes = d3_selectAll('.map-pane.shown');

        var side = textDirection === 'ltr' ? 'right' : 'left';

        shownPanes
            .classed('shown', false);

        d3_selectAll('.map-control button')
            .classed('active', false);

        if (showPane) {
            shownPanes
                .style('display', 'none')
                .style(side, '-500px');

            d3_selectAll('.' + showPane.attr('pane') + '-control button')
                .classed('active', true);

            showPane
                .classed('shown', true)
                .style('display', 'block');
            if (shownPanes.empty()) {
                showPane
                    .style('display', 'block')
                    .style(side, '-500px')
                    .transition()
                    .duration(200)
                    .style(side, '0px');
            } else {
                showPane
                    .style(side, '0px');
            }
        } else {
            shownPanes
                .style('display', 'block')
                .style(side, '0px')
                .transition()
                .duration(200)
                .style(side, '-500px')
                .on('end', function() {
                    d3_select(this).style('display', 'none');
                });
        }
    };

    return ui;
}
<commit_msg>Don't draw until we've set zoom/lat/long<commit_after>import {
    event as d3_event,
    select as d3_select,
    selectAll as d3_selectAll
} from 'd3-selection';

import { t, textDirection } from '../util/locale';
import { tooltip } from '../util/tooltip';

import { behaviorHash } from '../behavior';
import { modeBrowse } from '../modes/browse';
import { svgDefs, svgIcon } from '../svg';
import { utilGetDimensions } from '../util/dimensions';

import { uiAccount } from './account';
import { uiAttribution } from './attribution';
import { uiBackground } from './background';
import { uiContributors } from './contributors';
import { uiFeatureInfo } from './feature_info';
import { uiFullScreen } from './full_screen';
import { uiGeolocate } from './geolocate';
import { uiHelp } from './help';
import { uiInfo } from './info';
import { uiIntro } from './intro';
import { uiIssues } from './issues';
import { uiLoading } from './loading';
import { uiMapData } from './map_data';
import { uiMapInMap } from './map_in_map';
import { uiNotice } from './notice';
import { uiPhotoviewer } from './photoviewer';
import { uiRestore } from './restore';
import { uiScale } from './scale';
import { uiShortcuts } from './shortcuts';
import { uiSidebar } from './sidebar';
import { uiSpinner } from './spinner';
import { uiSplash } from './splash';
import { uiStatus } from './status';
import { uiTopToolbar } from './top_toolbar';
import { uiVersion } from './version';
import { uiZoom } from './zoom';
import { uiCmd } from './cmd';

export function uiInit(context) {
    var _initCounter = 0;
    var _initCallback;
    var _needWidth = {};

    function render(container) {
        container
            .attr('dir', textDirection);

        // setup fullscreen keybindings (no button shown at this time)
        container
            .call(uiFullScreen(context));

        var map = context.map();
        map.redrawEnable(false);  // don't draw until we've set zoom/lat/long

        container
            .append('svg')
            .attr('id', 'defs')
            .call(svgDefs(context));

        container
            .append('div')
            .attr('id', 'sidebar')
            .call(ui.sidebar);

        var content = container
            .append('div')
            .attr('id', 'content')
            .attr('class', 'active');

        // Top toolbar
        content
            .append('div')
            .attr('id', 'bar')
            .attr('class', 'fillD')
            .call(uiTopToolbar(context));

        content
            .append('div')
            .attr('id', 'map')
            .attr('dir', 'ltr')
            .call(map);

        // Map controls
        var controls = content
            .append('div')
            .attr('class', 'map-controls');

        controls
            .append('div')
            .attr('class', 'map-control zoombuttons')
            .call(uiZoom(context));

        controls
            .append('div')
            .attr('class', 'map-control geolocate-control')
            .call(uiGeolocate(context));

        var background = uiBackground(context);
        controls
            .append('div')
            .attr('class', 'map-control background-control')
            .call(background.renderToggleButton);

        var mapData = uiMapData(context);
        controls
            .append('div')
            .attr('class', 'map-control map-data-control')
            .call(mapData.renderToggleButton);

        var issues = uiIssues(context);
        controls
            .append('div')
            .attr('class', 'map-control map-issues-control')
            .call(issues.renderToggleButton);

        var help = uiHelp(context);
        controls
            .append('div')
            .attr('class', 'map-control help-control')
            .call(help.renderToggleButton);

        content
            .append('div')
            .attr('class', 'spinner')
            .call(uiSpinner(context));

        // Add attribution and footer
        var about = content
            .append('div')
            .attr('id', 'about');

        about
            .append('div')
            .attr('id', 'attrib')
            .attr('dir', 'ltr')
            .call(uiAttribution(context));

        about
            .append('div')
            .attr('class', 'api-status')
            .call(uiStatus(context));

        var footer = about
            .append('div')
            .attr('id', 'footer')
            .attr('class', 'fillD');

        footer
            .append('div')
            .attr('id', 'flash-wrap')
            .attr('class', 'footer-hide');

        var footerWrap = footer
            .append('div')
            .attr('id', 'footer-wrap')
            .attr('class', 'footer-show');

        footerWrap
            .append('div')
            .attr('id', 'scale-block')
            .call(uiScale(context));

        var aboutList = footerWrap
            .append('div')
            .attr('id', 'info-block')
            .append('ul')
            .attr('id', 'about-list');

        if (!context.embed()) {
            aboutList
                .call(uiAccount(context));
        }

        aboutList
            .append('li')
            .attr('class', 'version')
            .call(uiVersion(context));

        var issueLinks = aboutList
            .append('li');

        issueLinks
            .append('a')
            .attr('target', '_blank')
            .attr('tabindex', -1)
            .attr('href', 'https://github.com/openstreetmap/iD/issues')
            .call(svgIcon('#iD-icon-bug', 'light'))
            .call(tooltip().title(t('report_a_bug')).placement('top'));

        issueLinks
            .append('a')
            .attr('target', '_blank')
            .attr('tabindex', -1)
            .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
            .call(svgIcon('#iD-icon-translate', 'light'))
            .call(tooltip().title(t('help_translate')).placement('top'));

        aboutList
            .append('li')
            .attr('class', 'feature-warning')
            .attr('tabindex', -1)
            .call(uiFeatureInfo(context));

        aboutList
            .append('li')
            .attr('class', 'user-list')
            .attr('tabindex', -1)
            .call(uiContributors(context));

        // Setup map dimensions and move map to initial center/zoom.
        // This should happen after #content and toolbars exist.
        ui.onResize();
        map.redrawEnable(true);

        var hash = behaviorHash(context);
        hash();
        if (!hash.hadHash) {
            map.centerZoom([0, 0], 2);
        }

        var overMap = content
            .append('div')
            .attr('class', 'over-map');

        // Add panes
        // This should happen after map is initialized, as some require surface()
        var panes = overMap
            .append('div')
            .attr('class', 'map-panes');

        panes
            .call(background.renderPane)
            .call(mapData.renderPane)
            .call(issues.renderPane)
            .call(help.renderPane);

        // Add absolutely-positioned elements that sit on top of the map
        // This should happen after the map is ready (center/zoom)
        overMap
            .call(uiMapInMap(context))
            .call(uiInfo(context))
            .call(uiNotice(context));

        overMap
            .append('div')
            .attr('id', 'photoviewer')
            .classed('al', true)       // 'al'=left,  'ar'=right
            .classed('hide', true)
            .call(ui.photoviewer);

        // Bind events
        window.onbeforeunload = function() {
            return context.save();
        };
        window.onunload = function() {
            context.history().unlock();
        };

        d3_select(window)
            .on('gesturestart.editor', eventCancel)
            .on('gesturechange.editor', eventCancel)
            .on('gestureend.editor', eventCancel)
            .on('resize.editor', ui.onResize);

        var panPixels = 80;
        context.keybinding()
            .on('⌫', function() { d3_event.preventDefault(); })
            .on([t('sidebar.key'), '`', '²'], ui.sidebar.toggle)   // #5663 - common QWERTY, AZERTY
            .on('←', pan([panPixels, 0]))
            .on('↑', pan([0, panPixels]))
            .on('→', pan([-panPixels, 0]))
            .on('↓', pan([0, -panPixels]))
            .on(['⇧←', uiCmd('⌘←')], pan([map.dimensions()[0], 0]))
            .on(['⇧↑', uiCmd('⌘↑')], pan([0, map.dimensions()[1]]))
            .on(['⇧→', uiCmd('⌘→')], pan([-map.dimensions()[0], 0]))
            .on(['⇧↓', uiCmd('⌘↓')], pan([0, -map.dimensions()[1]]));

        context.enter(modeBrowse(context));

        if (!_initCounter++) {
            if (!hash.startWalkthrough) {
                context.container()
                    .call(uiSplash(context))
                    .call(uiRestore(context));
            }

            context.container()
                .call(uiShortcuts(context));
        }

        var osm = context.connection();
        var auth = uiLoading(context).message(t('loading_auth')).blocking(true);

        if (osm && auth) {
            osm
                .on('authLoading.ui', function() {
                    context.container()
                        .call(auth);
                })
                .on('authDone.ui', function() {
                    auth.close();
                });
        }

        _initCounter++;

        if (hash.startWalkthrough) {
            hash.startWalkthrough = false;
            context.container().call(uiIntro(context));
        }

        function pan(d) {
            return function() {
                if (d3_select('.combobox').size()) return;
                d3_event.preventDefault();
                context.pan(d, 100);
            };
        }

        function eventCancel() {
            d3_event.preventDefault();
        }
    }

    function ui(node, callback) {
        _initCallback = callback;
        var container = d3_select(node);
        context.container(container);
        context.loadLocale(function(err) {
            if (!err) {
                render(container);
            }
            if (callback) {
                callback(err);
            }
        });
    }

    ui.restart = function(arg) {
        context.keybinding().clear();
        context.locale(arg);
        context.loadLocale(function(err) {
            if (!err) {
                context.container().selectAll('*').remove();
                render(context.container());
                if (_initCallback) _initCallback();
            }
        });
    };

    ui.sidebar = uiSidebar(context);

    ui.photoviewer = uiPhotoviewer(context);

    ui.onResize = function(withPan) {
        var map = context.map();

        // Recalc dimensions of map and sidebar.. (`true` = force recalc)
        // This will call `getBoundingClientRect` and trigger reflow,
        //  but the values will be cached for later use.
        var mapDimensions = utilGetDimensions(d3_select('#content'), true);
        utilGetDimensions(d3_select('#sidebar'), true);

        if (withPan !== undefined) {
            map.redrawEnable(false);
            map.pan(withPan);
            map.redrawEnable(true);
        }
        map.dimensions(mapDimensions);

        ui.photoviewer.onMapResize();

        // check if header or footer have overflowed
        ui.checkOverflow('#bar');
        ui.checkOverflow('#footer');

        // Use outdated code so it works on Explorer
        var resizeWindowEvent = document.createEvent('Event');

        resizeWindowEvent.initEvent('resizeWindow', true, true);

        document.dispatchEvent(resizeWindowEvent);
    };

    // Call checkOverflow when resizing or whenever the contents change.
    ui.checkOverflow = function(selector, reset) {
        if (reset) {
            delete _needWidth[selector];
        }

        var element = d3_select(selector);
        var scrollWidth = element.property('scrollWidth');
        var clientWidth = element.property('clientWidth');
        var needed = _needWidth[selector] || scrollWidth;

        if (scrollWidth > clientWidth) {    // overflow happening
            element.classed('narrow', true);
            if (!_needWidth[selector]) {
                _needWidth[selector] = scrollWidth;
            }

        } else if (scrollWidth >= needed) {
            element.classed('narrow', false);
        }
    };

    ui.togglePanes = function(showPane) {
        var shownPanes = d3_selectAll('.map-pane.shown');

        var side = textDirection === 'ltr' ? 'right' : 'left';

        shownPanes
            .classed('shown', false);

        d3_selectAll('.map-control button')
            .classed('active', false);

        if (showPane) {
            shownPanes
                .style('display', 'none')
                .style(side, '-500px');

            d3_selectAll('.' + showPane.attr('pane') + '-control button')
                .classed('active', true);

            showPane
                .classed('shown', true)
                .style('display', 'block');
            if (shownPanes.empty()) {
                showPane
                    .style('display', 'block')
                    .style(side, '-500px')
                    .transition()
                    .duration(200)
                    .style(side, '0px');
            } else {
                showPane
                    .style(side, '0px');
            }
        } else {
            shownPanes
                .style('display', 'block')
                .style(side, '0px')
                .transition()
                .duration(200)
                .style(side, '-500px')
                .on('end', function() {
                    d3_select(this).style('display', 'none');
                });
        }
    };

    return ui;
}
<|endoftext|>