<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

UI.Texture = function ( mapping ) {

	UI.Element.call( this );

	var scope = this;

	var dom = document.createElement( 'span' );

	var form = document.createElement( 'form' );

	var input = document.createElement( 'input' );
	input.type = 'file';
	input.addEventListener( 'change', function ( event ) {

		loadFile( event.target.files[ 0 ] );

	} );
	form.appendChild( input );

	var canvas = document.createElement( 'canvas' );
	canvas.width = 32;
	canvas.height = 16;
	canvas.style.cursor = 'pointer';
	canvas.style.marginRight = '5px';
	canvas.style.border = '1px solid #888';
	canvas.addEventListener( 'click', function ( event ) {

		input.click();

	}, false );
	canvas.addEventListener( 'drop', function ( event ) {

		event.preventDefault();
		event.stopPropagation();
		loadFile( event.dataTransfer.files[ 0 ] );

	}, false );
	dom.appendChild( canvas );

	var name = document.createElement( 'input' );
	name.disabled = true;
	name.style.width = '64px';
	name.style.border = '1px solid #ccc';
	dom.appendChild( name );

	function loadFile( file ) {

		if ( file.type.match( 'image.*' ) ) {

			var reader = new FileReader();

			if ( file.type === 'image/targa' ) {

				reader.addEventListener( 'load', function ( event ) {

					var canvas = new THREE.TGALoader().parse( event.target.result );

					var texture = new THREE.CanvasTexture( canvas, mapping );
					texture.sourceFile = file.name;

					scope.setValue( texture );

					if ( scope.onChangeCallback ) scope.onChangeCallback();

				}, false );

				reader.readAsArrayBuffer( file );

			} else {

				reader.addEventListener( 'load', function ( event ) {

					var image = document.createElement( 'img' );
					image.addEventListener( 'load', function( event ) {

						var texture = new THREE.Texture( this, mapping );
						texture.sourceFile = file.name;
						texture.format = file.type === 'image/jpeg' ? THREE.RGBFormat : THREE.RGBAFormat;
						texture.needsUpdate = true;

						scope.setValue( texture );

						if ( scope.onChangeCallback ) scope.onChangeCallback();

					}, false );

					image.src = event.target.result;

				}, false );

				reader.readAsDataURL( file );

			}

		}

		form.reset();

	}

	this.dom = dom;
	this.texture = null;
	this.onChangeCallback = null;

	return this;

};

UI.Texture.prototype = Object.create( UI.Element.prototype );
UI.Texture.prototype.constructor = UI.Texture;

UI.Texture.prototype.getValue = function () {

	return this.texture;

};

UI.Texture.prototype.setValue = function ( texture ) {

	var canvas = this.dom.children[ 0 ];
	var name = this.dom.children[ 1 ];
	var context = canvas.getContext( '2d' );

	if ( texture !== null ) {

		var image = texture.image;

		if ( image !== undefined && image.width > 0 ) {

			name.value = texture.sourceFile;

			var scale = canvas.width / image.width;
			context.drawImage( image, 0, 0, image.width * scale, image.height * scale );

		} else {

			name.value = texture.sourceFile + ' (error)';
			context.clearRect( 0, 0, canvas.width, canvas.height );

		}

	} else {

		name.value = '';

		if ( context !== null ) {

			// Seems like context can be null if the canvas is not visible

			context.clearRect( 0, 0, canvas.width, canvas.height );

		}

	}

	this.texture = texture;

};

UI.Texture.prototype.onChange = function ( callback ) {

	this.onChangeCallback = callback;

	return this;

};

// Outliner

UI.Outliner = function ( editor ) {

	UI.Element.call( this );

	var scope = this;

	var dom = document.createElement( 'div' );
	dom.className = 'Outliner';
	dom.tabIndex = 0;	// keyup event is ignored without setting tabIndex

	// hack
	this.scene = editor.scene;

	// Prevent native scroll behavior
	dom.addEventListener( 'keydown', function ( event ) {

		switch ( event.keyCode ) {
			case 38: // up
			case 40: // down
				event.preventDefault();
				event.stopPropagation();
				break;
		}

	}, false );

	// Keybindings to support arrow navigation
	dom.addEventListener( 'keyup', function ( event ) {

		switch ( event.keyCode ) {
			case 38: // up
				scope.selectIndex( scope.selectedIndex - 1 );
				break;
			case 40: // down
				scope.selectIndex( scope.selectedIndex + 1 );
				break;
		}

	}, false );

	this.dom = dom;

	this.options = [];
	this.selectedIndex = - 1;
	this.selectedValue = null;

	return this;

};

UI.Outliner.prototype = Object.create( UI.Element.prototype );
UI.Outliner.prototype.constructor = UI.Outliner;

UI.Outliner.prototype.selectIndex = function ( index ) {

	if ( index >= 0 && index < this.options.length ) {

		this.setValue( this.options[ index ].value );

		var changeEvent = document.createEvent( 'HTMLEvents' );
		changeEvent.initEvent( 'change', true, true );
		this.dom.dispatchEvent( changeEvent );

	}

};

UI.Outliner.prototype.setOptions = function ( options ) {

	var scope = this;

	while ( scope.dom.children.length > 0 ) {

		scope.dom.removeChild( scope.dom.firstChild );

	}

	function onClick() {

		scope.setValue( this.value );

		var changeEvent = document.createEvent( 'HTMLEvents' );
		changeEvent.initEvent( 'change', true, true );
		scope.dom.dispatchEvent( changeEvent );

	}

	// Drag

	var currentDrag;

	function onDrag( event ) {

		currentDrag = this;

	}

	function onDragStart( event ) {

		event.dataTransfer.setData( 'text', 'foo' );

	}

	function onDragOver( event ) {

		if ( this === currentDrag ) return;

		var area = event.offsetY / this.clientHeight;

		if ( area < 0.25 ) {

			this.className = 'option dragTop';

		} else if ( area > 0.75 ) {

			this.className = 'option dragBottom';

		} else {

			this.className = 'option drag';

		}

	}

	function onDragLeave() {

		if ( this === currentDrag ) return;

		this.className = 'option';

	}

	function onDrop( event ) {

		if ( this === currentDrag ) return;

		this.className = 'option';

		var scene = scope.scene;
		var object = scene.getObjectById( currentDrag.value );

		var area = event.offsetY / this.clientHeight;

		if ( area < 0.25 ) {

			var nextObject = scene.getObjectById( this.value );
			moveObject( object, nextObject.parent, nextObject );

		} else if ( area > 0.75 ) {

			var nextObject = scene.getObjectById( this.nextSibling.value );
			moveObject( object, nextObject.parent, nextObject );

		} else {

			var parentObject = scene.getObjectById( this.value );
			moveObject( object, parentObject );

		}

	}

	function moveObject( object, newParent, nextObject ) {

		if ( nextObject === null ) nextObject = undefined;

		var newParentIsChild = false;

		object.traverse( function ( child ) {

			if ( child === newParent ) newParentIsChild = true;

		} );

		if ( newParentIsChild ) return;

		editor.execute( new MoveObjectCommand( object, newParent, nextObject ) );

		var changeEvent = document.createEvent( 'HTMLEvents' );
		changeEvent.initEvent( 'change', true, true );
		scope.dom.dispatchEvent( changeEvent );

	}

	//

	scope.options = [];

	for ( var i = 0; i < options.length; i ++ ) {

		var div = options[ i ];
		div.className = 'option';
		scope.dom.appendChild( div );

		scope.options.push( div );

		div.addEventListener( 'click', onClick, false );

		if ( div.draggable === true ) {

			div.addEventListener( 'drag', onDrag, false );
			div.addEventListener( 'dragstart', onDragStart, false ); // Firefox needs this

			div.addEventListener( 'dragover', onDragOver, false );
			div.addEventListener( 'dragleave', onDragLeave, false );
			div.addEventListener( 'drop', onDrop, false );

		}

	}

	return scope;

};

UI.Outliner.prototype.getValue = function () {

	return this.selectedValue;

};

UI.Outliner.prototype.setValue = function ( value ) {

	for ( var i = 0; i < this.options.length; i ++ ) {

		var element = this.options[ i ];

		if ( element.value === value ) {

			element.classList.add( 'active' );

			// scroll into view

			var y = element.offsetTop - this.dom.offsetTop;
			var bottomY = y + element.offsetHeight;
			var minScroll = bottomY - this.dom.offsetHeight;

			if ( this.dom.scrollTop > y ) {

				this.dom.scrollTop = y;

			} else if ( this.dom.scrollTop < minScroll ) {

				this.dom.scrollTop = minScroll;

			}

			this.selectedIndex = i;

		} else {

			element.classList.remove( 'active' );

		}

	}

	this.selectedValue = value;

	return this;

};

UI.THREE = {};

UI.THREE.Boolean = function ( boolean, text ) {

	UI.Span.call( this );

	this.setMarginRight( '10px' );

	this.checkbox = new UI.Checkbox( boolean );
	this.text = new UI.Text( text ).setMarginLeft( '3px' );

	this.add( this.checkbox );
	this.add( this.text );

};

UI.THREE.Boolean.prototype = Object.create( UI.Span.prototype );
UI.THREE.Boolean.prototype.constructor = UI.THREE.Boolean;

UI.THREE.Boolean.prototype.getValue = function () {

	return this.checkbox.getValue();

};

UI.THREE.Boolean.prototype.setValue = function ( value ) {

	return this.checkbox.setValue( value );

};
<commit_msg>Add UI.Points<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

UI.Texture = function ( mapping ) {

	UI.Element.call( this );

	var scope = this;

	var dom = document.createElement( 'span' );

	var form = document.createElement( 'form' );

	var input = document.createElement( 'input' );
	input.type = 'file';
	input.addEventListener( 'change', function ( event ) {

		loadFile( event.target.files[ 0 ] );

	} );
	form.appendChild( input );

	var canvas = document.createElement( 'canvas' );
	canvas.width = 32;
	canvas.height = 16;
	canvas.style.cursor = 'pointer';
	canvas.style.marginRight = '5px';
	canvas.style.border = '1px solid #888';
	canvas.addEventListener( 'click', function ( event ) {

		input.click();

	}, false );
	canvas.addEventListener( 'drop', function ( event ) {

		event.preventDefault();
		event.stopPropagation();
		loadFile( event.dataTransfer.files[ 0 ] );

	}, false );
	dom.appendChild( canvas );

	var name = document.createElement( 'input' );
	name.disabled = true;
	name.style.width = '64px';
	name.style.border = '1px solid #ccc';
	dom.appendChild( name );

	function loadFile( file ) {

		if ( file.type.match( 'image.*' ) ) {

			var reader = new FileReader();

			if ( file.type === 'image/targa' ) {

				reader.addEventListener( 'load', function ( event ) {

					var canvas = new THREE.TGALoader().parse( event.target.result );

					var texture = new THREE.CanvasTexture( canvas, mapping );
					texture.sourceFile = file.name;

					scope.setValue( texture );

					if ( scope.onChangeCallback ) scope.onChangeCallback();

				}, false );

				reader.readAsArrayBuffer( file );

			} else {

				reader.addEventListener( 'load', function ( event ) {

					var image = document.createElement( 'img' );
					image.addEventListener( 'load', function( event ) {

						var texture = new THREE.Texture( this, mapping );
						texture.sourceFile = file.name;
						texture.format = file.type === 'image/jpeg' ? THREE.RGBFormat : THREE.RGBAFormat;
						texture.needsUpdate = true;

						scope.setValue( texture );

						if ( scope.onChangeCallback ) scope.onChangeCallback();

					}, false );

					image.src = event.target.result;

				}, false );

				reader.readAsDataURL( file );

			}

		}

		form.reset();

	}

	this.dom = dom;
	this.texture = null;
	this.onChangeCallback = null;

	return this;

};

UI.Texture.prototype = Object.create( UI.Element.prototype );
UI.Texture.prototype.constructor = UI.Texture;

UI.Texture.prototype.getValue = function () {

	return this.texture;

};

UI.Texture.prototype.setValue = function ( texture ) {

	var canvas = this.dom.children[ 0 ];
	var name = this.dom.children[ 1 ];
	var context = canvas.getContext( '2d' );

	if ( texture !== null ) {

		var image = texture.image;

		if ( image !== undefined && image.width > 0 ) {

			name.value = texture.sourceFile;

			var scale = canvas.width / image.width;
			context.drawImage( image, 0, 0, image.width * scale, image.height * scale );

		} else {

			name.value = texture.sourceFile + ' (error)';
			context.clearRect( 0, 0, canvas.width, canvas.height );

		}

	} else {

		name.value = '';

		if ( context !== null ) {

			// Seems like context can be null if the canvas is not visible

			context.clearRect( 0, 0, canvas.width, canvas.height );

		}

	}

	this.texture = texture;

};

UI.Texture.prototype.onChange = function ( callback ) {

	this.onChangeCallback = callback;

	return this;

};

// Outliner

UI.Outliner = function ( editor ) {

	UI.Element.call( this );

	var scope = this;

	var dom = document.createElement( 'div' );
	dom.className = 'Outliner';
	dom.tabIndex = 0;	// keyup event is ignored without setting tabIndex

	// hack
	this.scene = editor.scene;

	// Prevent native scroll behavior
	dom.addEventListener( 'keydown', function ( event ) {

		switch ( event.keyCode ) {
			case 38: // up
			case 40: // down
				event.preventDefault();
				event.stopPropagation();
				break;
		}

	}, false );

	// Keybindings to support arrow navigation
	dom.addEventListener( 'keyup', function ( event ) {

		switch ( event.keyCode ) {
			case 38: // up
				scope.selectIndex( scope.selectedIndex - 1 );
				break;
			case 40: // down
				scope.selectIndex( scope.selectedIndex + 1 );
				break;
		}

	}, false );

	this.dom = dom;

	this.options = [];
	this.selectedIndex = - 1;
	this.selectedValue = null;

	return this;

};

UI.Outliner.prototype = Object.create( UI.Element.prototype );
UI.Outliner.prototype.constructor = UI.Outliner;

UI.Outliner.prototype.selectIndex = function ( index ) {

	if ( index >= 0 && index < this.options.length ) {

		this.setValue( this.options[ index ].value );

		var changeEvent = document.createEvent( 'HTMLEvents' );
		changeEvent.initEvent( 'change', true, true );
		this.dom.dispatchEvent( changeEvent );

	}

};

UI.Outliner.prototype.setOptions = function ( options ) {

	var scope = this;

	while ( scope.dom.children.length > 0 ) {

		scope.dom.removeChild( scope.dom.firstChild );

	}

	function onClick() {

		scope.setValue( this.value );

		var changeEvent = document.createEvent( 'HTMLEvents' );
		changeEvent.initEvent( 'change', true, true );
		scope.dom.dispatchEvent( changeEvent );

	}

	// Drag

	var currentDrag;

	function onDrag( event ) {

		currentDrag = this;

	}

	function onDragStart( event ) {

		event.dataTransfer.setData( 'text', 'foo' );

	}

	function onDragOver( event ) {

		if ( this === currentDrag ) return;

		var area = event.offsetY / this.clientHeight;

		if ( area < 0.25 ) {

			this.className = 'option dragTop';

		} else if ( area > 0.75 ) {

			this.className = 'option dragBottom';

		} else {

			this.className = 'option drag';

		}

	}

	function onDragLeave() {

		if ( this === currentDrag ) return;

		this.className = 'option';

	}

	function onDrop( event ) {

		if ( this === currentDrag ) return;

		this.className = 'option';

		var scene = scope.scene;
		var object = scene.getObjectById( currentDrag.value );

		var area = event.offsetY / this.clientHeight;

		if ( area < 0.25 ) {

			var nextObject = scene.getObjectById( this.value );
			moveObject( object, nextObject.parent, nextObject );

		} else if ( area > 0.75 ) {

			var nextObject = scene.getObjectById( this.nextSibling.value );
			moveObject( object, nextObject.parent, nextObject );

		} else {

			var parentObject = scene.getObjectById( this.value );
			moveObject( object, parentObject );

		}

	}

	function moveObject( object, newParent, nextObject ) {

		if ( nextObject === null ) nextObject = undefined;

		var newParentIsChild = false;

		object.traverse( function ( child ) {

			if ( child === newParent ) newParentIsChild = true;

		} );

		if ( newParentIsChild ) return;

		editor.execute( new MoveObjectCommand( object, newParent, nextObject ) );

		var changeEvent = document.createEvent( 'HTMLEvents' );
		changeEvent.initEvent( 'change', true, true );
		scope.dom.dispatchEvent( changeEvent );

	}

	//

	scope.options = [];

	for ( var i = 0; i < options.length; i ++ ) {

		var div = options[ i ];
		div.className = 'option';
		scope.dom.appendChild( div );

		scope.options.push( div );

		div.addEventListener( 'click', onClick, false );

		if ( div.draggable === true ) {

			div.addEventListener( 'drag', onDrag, false );
			div.addEventListener( 'dragstart', onDragStart, false ); // Firefox needs this

			div.addEventListener( 'dragover', onDragOver, false );
			div.addEventListener( 'dragleave', onDragLeave, false );
			div.addEventListener( 'drop', onDrop, false );

		}

	}

	return scope;

};

UI.Outliner.prototype.getValue = function () {

	return this.selectedValue;

};

UI.Outliner.prototype.setValue = function ( value ) {

	for ( var i = 0; i < this.options.length; i ++ ) {

		var element = this.options[ i ];

		if ( element.value === value ) {

			element.classList.add( 'active' );

			// scroll into view

			var y = element.offsetTop - this.dom.offsetTop;
			var bottomY = y + element.offsetHeight;
			var minScroll = bottomY - this.dom.offsetHeight;

			if ( this.dom.scrollTop > y ) {

				this.dom.scrollTop = y;

			} else if ( this.dom.scrollTop < minScroll ) {

				this.dom.scrollTop = minScroll;

			}

			this.selectedIndex = i;

		} else {

			element.classList.remove( 'active' );

		}

	}

	this.selectedValue = value;

	return this;

};

var Points = function ( onAddClicked ) {

	UI.Element.call( this );

	var span = new UI.Span().setDisplay( 'inline-block' );

	this.pointsList = new UI.Div();
	span.add( this.pointsList );

	var row = new UI.Row();
	span.add( row );

	var addPointButton = new UI.Button( '+' ).onClick( onAddClicked );
	row.add( addPointButton );

	this.update = function () {

		if ( this.onChangeCallback !== null ) {

			this.onChangeCallback();

		}

	}.bind(this);

	this.dom = span.dom;
	this.pointsUI = [];
	this.lastPointIdx = 0;
	this.onChangeCallback = null;
	return this;

};

Points.prototype = Object.create( UI.Element.prototype );
Points.prototype.constructor = Points;

Points.prototype.onChange = function ( callback ) {

	this.onChangeCallback = callback;

	return this;

};

Points.prototype.clear = function () {

	for ( var i = 0; i < this.pointsUI.length; ++ i ) {

		if ( this.pointsUI[ i ] ) {

			this.deletePointRow( i, true );

		}

	}

	this.lastPointIdx = 0;

};

Points.prototype.deletePointRow = function ( idx, dontUpdate ) {

	if ( ! this.pointsUI[ idx ] ) return;

	this.pointsList.remove( this.pointsUI[ idx ].row );
	this.pointsUI[ idx ] = null;

	if ( dontUpdate !== true ) {

		this.update();

	}

};

UI.Points2 = function(){
	UI.Element.call( this, UI.Points2.addRow.bind(this));

	return this;
}

UI.Points2.prototype = Object.create( Points.prototype );
UI.Points2.prototype.constructor = UI.Points2;

UI.Points2.addRow = function () {

	if ( this.pointsUI.length === 0 ) {

		this.pointsList.add( this.createPointRow( 0, 0 ) );

	} else {

		var point = this.pointsUI[ this.pointsUI.length - 1 ];

		this.pointsList.add( this.createPointRow( point.x.getValue(), point.y.getValue() ) );

	}

	this.update();

}

UI.Points2.prototype.getValue = function () {
	var points = [];
	var count = 0;

	for ( var i = 0; i < this.pointsUI.length; i ++ ) {

		var pointUI = this.pointsUI[ i ];

		if ( ! pointUI ) continue;

		points.push( new THREE.Vector2( pointUI.x.getValue(), pointUI.y.getValue() ) );
		++ count;
		pointUI.lbl.setValue( count );

	}

	return points;
}

UI.Points2.prototype.setValue = function ( points ) {

	this.clear();

	for ( var i = 0; i < points.length; i ++ ) {

		var point = points[ i ];
		this.pointsList.add( this.createPointRow( point.x, point.y ) );

	}

	this.update();
	return this;

};

UI.Points2.prototype.createPointRow = function ( x, y ) {

	var pointRow = new UI.Div();
	var lbl = new UI.Text( this.lastPointIdx + 1 ).setWidth( '20px' );
	var txtX = new UI.Number( x ).setWidth( '30px' ).onChange( this.update );
	var txtY = new UI.Number( y ).setWidth( '30px' ).onChange( this.update );

	var idx = this.lastPointIdx;
	var scope = this;
	var btn = new UI.Button( '-' ).onClick( function () {

		if ( scope.isEditing ) return;
		scope.deletePointRow( idx );

	} );

	this.pointsUI.push(  { row: pointRow, lbl: lbl, x: txtX, y: txtY } );
	++ this.lastPointIdx;
	pointRow.add( lbl, txtX, txtY, btn );

	return pointRow;

};

UI.Points3 = function(){
	UI.Element.call( this, UI.Points3.addRow.bind(this));

	return this;
}

UI.Points3.prototype = Object.create( Points.prototype );
UI.Points3.prototype.constructor = UI.Points3;

UI.Points3.addRow = function () {

	if ( this.pointsUI.length === 0 ) {

		this.pointsList.add( this.createPointRow( 0, 0, 0 ) );

	} else {

		var point = this.pointsUI[ this.pointsUI.length - 1 ];

		this.pointsList.add( this.createPointRow( point.x.getValue(), point.y.getValue(), point.z.getValue() ) );

	}

	this.update();

}

UI.Points3.prototype.getValue = function () {
	var points = [];
	var count = 0;

	for ( var i = 0; i < this.pointsUI.length; i ++ ) {

		var pointUI = this.pointsUI[ i ];

		if ( ! pointUI ) continue;

		points.push( new THREE.Vector3( pointUI.x.getValue(), pointUI.y.getValue(), pointUI.z.getValue() ) );
		++ count;
		pointUI.lbl.setValue( count );

	}

	return points;
}

UI.Points3.prototype.setValue = function ( points ) {

	this.clear();

	for ( var i = 0; i < points.length; i ++ ) {

		var point = points[ i ];
		this.pointsList.add( this.createPointRow( point.x, point.y, point.z ) );

	}

	this.update();
	return this;

};

UI.Points3.prototype.createPointRow = function ( x, y, z ) {

	var pointRow = new UI.Div();
	var lbl = new UI.Text( this.lastPointIdx + 1 ).setWidth( '20px' );
	var txtX = new UI.Number( x ).setWidth( '30px' ).onChange( this.update );
	var txtY = new UI.Number( y ).setWidth( '30px' ).onChange( this.update );
	var txtZ = new UI.Number( z ).setWidth( '30px' ).onChange( this.update );

	var idx = this.lastPointIdx;
	var scope = this;
	var btn = new UI.Button( '-' ).onClick( function () {

		if ( scope.isEditing ) return;
		scope.deletePointRow( idx );

	} );

	this.pointsUI.push(  { row: pointRow, lbl: lbl, x: txtX, y: txtY, z : txtZ } );
	++ this.lastPointIdx;
	pointRow.add( lbl, txtX, txtY, txtZ, btn );

	return pointRow;

};

UI.THREE = {};

UI.THREE.Boolean = function ( boolean, text ) {

	UI.Span.call( this );

	this.setMarginRight( '10px' );

	this.checkbox = new UI.Checkbox( boolean );
	this.text = new UI.Text( text ).setMarginLeft( '3px' );

	this.add( this.checkbox );
	this.add( this.text );

};

UI.THREE.Boolean.prototype = Object.create( UI.Span.prototype );
UI.THREE.Boolean.prototype.constructor = UI.THREE.Boolean;

UI.THREE.Boolean.prototype.getValue = function () {

	return this.checkbox.getValue();

};

UI.THREE.Boolean.prototype.setValue = function ( value ) {

	return this.checkbox.setValue( value );

};
<|endoftext|>


<commit_before>/* This file is part of Indico.
 * Copyright (C) 2002 - 2018 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

/* global ExclusivePopup:false, showFormErrors:false, initForms:false */
/* eslint-disable max-len */

(function(global, $) {
    'use strict';

    // Ajaxifies a link to open the target page (which needs to be using jsonify_template or
    // WPJinjaMixin.render_template) in a  modal dialog. Any forms on the page are ajaxified and should be using
    // redirect_or_jsonify() (when used with WPJinjaMixin) or jsonify_data (when used with jsonify_template)
    // in case of success (or just return a JSON response containing success=true and possibly flashed messages).
    // The link target MUST point to a page which is also valid when loaded directly in the browser since the
    // link could still be opened in a new tab manually. If you don't have a non-AJAX version, place the url in
    // data-href.
    $.fn.ajaxDialog = function jqAjaxDialog(options) {
        return this.on('click', function(e) {
            e.preventDefault();
            if ($(this).hasClass('disabled')) {
                return;
            }
            var href = $(this).attr('href');
            if (href === undefined || href === '#') {
                var dataHref = $(this).data('href');
                href = dataHref ? dataHref : href;
            }
            ajaxDialog($.extend({
                title: $(this).data('title')
            }, options, {
                url: href,
                trigger: this
            }));
        });
    };

    // See the documentation of $.fn.ajaxDialog - use this function if you want to open an ajax-based dialog
    // manually instead of triggering it from a link using its href.
    global.ajaxDialog = function ajaxDialog(options) {
        options = $.extend({
            trigger: null, // element that opened the dialog
            title: null, // title of the dialog
            subtitle: null, // subtitle of the dialog
            closeButton: undefined, // include a close button at the bottom of the dialog. the inner text of the button
                                    // is configurable
            url: null, // url to get the content from
            content: null, // content of the dialog (used instead of the url option)
            method: 'GET', // http method to get the form/dialog
            data: null, // object or callable to add data when loading the form/dialog
            backSelector: '[data-button-back]', // elements in the form which will close the form
            clearFlashes: true, // clear existing flashed messages before showing new ones
            onClose: null, // callback to invoke after closing the dialog. first argument is null if closed manually,
                           // otherwise the JSON returned by the server. if it returns false, the dialog will remain
                           // open; if it returns a Deferred object, the dialog remain open until the object is resolved
            onOpen: null,  // callback to invoke after opening the dialog.
            onLoadError: null,  // callback to invoke when loading the dialog fails.  receives the jqxhr object as an
                                // argument.  if the function returns false, the default error handler is not invoked.
            onError: null, // callback to invoke after triggering ajaxDialog:close event
            getExtraData: function() {},  // callback to add data to the form. receives the <form> element as `this`
            confirmCloseUnsaved: false,  // ask the user to confirm closing the dialog with unsaved changes
            dialogClasses: '',  // extra classes to add to the dialog canvas
            hidePageHeader: false,  // if the default page header (title/subtitle/description) should be hidden
            fullyModal: false  // Makes the dialog the only scrollable element
        }, options);

        var confirmCloseMessage = $T('You have unsaved changes. Do you really want to close the dialog without saving?');
        var popup = null;
        var customData = null;
        var oldOnBeforeUnload = null;
        var ignoreOnBeforeUnload = false;

        loadDialog();

        function loadDialog() {
            if (options.content) {
                showDialog({js: '', html: options.content});
                return;
            }
            $.ajax({
                type: options.method,
                url: options.url,
                data: $.isFunction(options.data) ? options.data() : options.data,
                cache: false, // IE caches GET AJAX requests. WTF.
                complete: IndicoUI.Dialogs.Util.progress(),
                error: function(xhr) {
                    var handled = false;
                    if (options.onLoadError && options.onLoadError(xhr) === false) {
                        handled = true;
                    }
                    if (options.trigger) {
                        var evt = $.Event('ajaxDialog:loadError');
                        $(options.trigger).trigger(evt, [xhr]);
                        if (evt.isDefaultPrevented()) {
                            handled = true;
                        }
                    }
                    if (!handled) {
                        handleAjaxError(xhr);
                    }
                },
                success: function(data, _, xhr) {
                    if (handleAjaxError(data)) {
                        return;
                    }
                    var loadedURL = xhr.getResponseHeader('X-Indico-URL');
                    if (loadedURL) {
                        // in case of a redirect we need to update the url used to submit the ajaxified
                        // form. otherwise url normalization might fail during the POST requests.
                        // we also remove the _=\d+ cache buster since it's only relevant for the GET
                        // request and added there automatically
                        options.url = loadedURL.replace(/&_=\d+/, '').replace(/\?_=\d+$/, '').replace(/\?_=\d+&/, '?');
                    }
                    showDialog(data);
                }
            });
        }

        function hasChangedFields() {
            var forms = popup.contentContainer.find('form');
            return forms.length && !!forms.filter(function() {
                return $(this).data('fieldsChanged');
            }).length;
        }

        function confirmClose() {
            return hasChangedFields() ? confirmPrompt(confirmCloseMessage, $T('Unsaved changes')) : $.Deferred().resolve();
        }

        function showDialog(dialogData) {
            if (popup) {
                _doCloseDialog();
            }
            popup = new ExclusivePopup($.isFunction(options.title) ? options.title.call(options.trigger) : options.title, function() {
                closeDialog(null);
                return false;
            }, false, false);

            popup.draw = function() {
                if (options.trigger && $(options.trigger).closest('.event-locked').length) {
                    this.canvas.addClass('event-locked');
                }
                this.ExclusivePopup.prototype.draw.call(this, dialogData.html);
                if (options.subtitle) {
                    this.canvas.prepend($('<div>', {
                        class: 'dialog-subtitle',
                        text: options.subtitle
                    }));
                }
                if (options.closeButton !== undefined && options.closeButton !== false) {
                    var text = options.closeButton === true ? $T.gettext("Close") : options.closeButton;
                    this.contentContainer.append($('<button>', {
                        'class': 'i-button big right',
                        'type': 'button',
                        'text': text,
                        'data-button-back': ''
                    }));
                }
            };

            popup.postDraw = function() {
                ajaxifyForms();
                popup.canvas.on('ajaxDialog:setData', function(e, data) {
                    customData = data;
                });
                popup.canvas.on('ajaxDialog:close', function(e, data, submitted) {
                    closeDialog(data, submitted);
                });
                popup.canvas.on('ajaxDialog:reload', function() {
                    loadDialog();
                });
                injectJS(dialogData.js);
                _onOpen();
                _.defer(function() {
                    popup.canvas.focusFirstField();
                });

                return true;
            };

            var dialogClasses = _.union(['dialog-window', options.dialogClasses]);
            if (options.hidePageHeader) {
                dialogClasses.push('no-page-header');
            }
            popup.canvas.addClass(dialogClasses.join(' '));

            if (options.confirmCloseUnsaved) {
                oldOnBeforeUnload = window.onbeforeunload;
                window.onbeforeunload = function() {
                    if (popup.isopen && !ignoreOnBeforeUnload && hasChangedFields()) {
                        return confirmCloseMessage;
                    }
                };
            }

            popup.open();
        }

        function closeDialog(callbackData, submitted) {
            var confirmDeferred = (submitted || !options.confirmCloseUnsaved) ? $.Deferred().resolve() : confirmClose();
            confirmDeferred.then(function() {
                ignoreOnBeforeUnload = true;
                var onCloseResult = _onClose(callbackData);
                if (onCloseResult === false) {
                    ignoreOnBeforeUnload = false;
                    return;
                } else if (!onCloseResult || onCloseResult === true) {
                    onCloseResult = $.Deferred().resolve();
                }
                onCloseResult.then(function() {
                    _doCloseDialog();
                    if (options.trigger) {
                        $(options.trigger).trigger('ajaxDialog:closed', [callbackData, customData]);
                    }
                }, function() {
                    ignoreOnBeforeUnload = false;
                });
            });
        }

        function _doCloseDialog() {
            popup.close();
            if (options.confirmCloseUnsaved) {
                window.onbeforeunload = oldOnBeforeUnload;
            }
            popup = null;
        }

        function _onOpen() {
            if (options.fullyModal) {
                $('html, body').addClass('prevent-scrolling');
            }
            if (options.onOpen) {
                options.onOpen(popup);
            }
        }

        function _onClose(callbackData) {
            if (options.fullyModal) {
                $('html, body').removeClass('prevent-scrolling');
            }
            if (!options.onClose) {
                return $.Deferred().resolve();
            } else {
                return options.onClose(callbackData, customData);
            }
        }

        function ajaxifyForms() {
            var killProgress = null;
            popup.contentContainer.on('click', options.backSelector, function(e) {
                e.preventDefault();
                closeDialog();
            });
            var forms = popup.contentContainer.find('form');
            showFormErrors(popup.resultContainer);
            initForms(forms);
            forms.filter(':not([data-no-ajax])').each(function() {
                var $this = $(this);
                $this.on('ajaxForm:beforeSubmit', function() {
                    killProgress = IndicoUI.Dialogs.Util.progress();
                }).on('ajaxForm:error', function(e, xhr) {
                    if (killProgress) {
                        killProgress();
                    }
                    e.preventDefault();
                    if ($.isFunction(options.onError)) {
                        options.onError.call($this, xhr);
                    } else {
                        handleAjaxError(xhr);
                    }
                }).on('ajaxForm:success', function(e, data) {
                    if (killProgress) {
                        killProgress();
                    }
                    if (handleAjaxError(data)) {
                        return;
                    }

                    handleFlashes(data, options.clearFlashes, options.trigger ? $(options.trigger) : null);

                    if (data.close_dialog || data.success) {
                        closeDialog(data, true);
                        if (data.redirect) {
                            if (!data.redirect_no_loading) {
                                IndicoUI.Dialogs.Util.progress();
                            }
                            location.href = data.redirect;
                        }
                    } else if (data.html) {
                        popup.contentContainer.html(data.html);
                        ajaxifyForms();
                        injectJS(data.js);
                    }
                });
                // We often use forms with an empty action; those need to go to
                // their page and not the page that loaded the dialog!
                var action = $this.attr('action') || options.url;
                $this.ajaxForm({
                    url: action,
                    dataType: 'json',
                    data: options.getExtraData.call(this, options.trigger),
                    beforeSubmit: function() {
                        var evt = $.Event('ajaxForm:validateBeforeSubmit');
                        $this.trigger(evt);
                        if (evt.isDefaultPrevented()) {
                            return false;
                        }
                        $this.trigger('ajaxForm:beforeSubmit');
                    },
                    error: function(xhr) {
                        $this.trigger('ajaxForm:error', [xhr]);
                    },
                    success: function(data) {
                        $this.trigger('ajaxForm:success', [data]);
                    }
                });
            });
        }

        function injectJS(js) {
            if (js) {
                $('body').append(js);
            }
        }
    };
})(window, jQuery);
<commit_msg>Avoid prompt on the abstract submission<commit_after>/* This file is part of Indico.
 * Copyright (C) 2002 - 2018 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

/* global ExclusivePopup:false, showFormErrors:false, initForms:false */
/* eslint-disable max-len */

(function(global, $) {
    'use strict';

    // Ajaxifies a link to open the target page (which needs to be using jsonify_template or
    // WPJinjaMixin.render_template) in a  modal dialog. Any forms on the page are ajaxified and should be using
    // redirect_or_jsonify() (when used with WPJinjaMixin) or jsonify_data (when used with jsonify_template)
    // in case of success (or just return a JSON response containing success=true and possibly flashed messages).
    // The link target MUST point to a page which is also valid when loaded directly in the browser since the
    // link could still be opened in a new tab manually. If you don't have a non-AJAX version, place the url in
    // data-href.
    $.fn.ajaxDialog = function jqAjaxDialog(options) {
        return this.on('click', function(e) {
            e.preventDefault();
            if ($(this).hasClass('disabled')) {
                return;
            }
            var href = $(this).attr('href');
            if (href === undefined || href === '#') {
                var dataHref = $(this).data('href');
                href = dataHref ? dataHref : href;
            }
            ajaxDialog($.extend({
                title: $(this).data('title')
            }, options, {
                url: href,
                trigger: this
            }));
        });
    };

    // See the documentation of $.fn.ajaxDialog - use this function if you want to open an ajax-based dialog
    // manually instead of triggering it from a link using its href.
    global.ajaxDialog = function ajaxDialog(options) {
        options = $.extend({
            trigger: null, // element that opened the dialog
            title: null, // title of the dialog
            subtitle: null, // subtitle of the dialog
            closeButton: undefined, // include a close button at the bottom of the dialog. the inner text of the button
                                    // is configurable
            url: null, // url to get the content from
            content: null, // content of the dialog (used instead of the url option)
            method: 'GET', // http method to get the form/dialog
            data: null, // object or callable to add data when loading the form/dialog
            backSelector: '[data-button-back]', // elements in the form which will close the form
            clearFlashes: true, // clear existing flashed messages before showing new ones
            onClose: null, // callback to invoke after closing the dialog. first argument is null if closed manually,
                           // otherwise the JSON returned by the server. if it returns false, the dialog will remain
                           // open; if it returns a Deferred object, the dialog remain open until the object is resolved
            onOpen: null,  // callback to invoke after opening the dialog.
            onLoadError: null,  // callback to invoke when loading the dialog fails.  receives the jqxhr object as an
                                // argument.  if the function returns false, the default error handler is not invoked.
            onError: null, // callback to invoke after triggering ajaxDialog:close event
            getExtraData: function() {},  // callback to add data to the form. receives the <form> element as `this`
            confirmCloseUnsaved: false,  // ask the user to confirm closing the dialog with unsaved changes
            dialogClasses: '',  // extra classes to add to the dialog canvas
            hidePageHeader: false,  // if the default page header (title/subtitle/description) should be hidden
            fullyModal: false  // Makes the dialog the only scrollable element
        }, options);

        var confirmCloseMessage = $T('You have unsaved changes. Do you really want to close the dialog without saving?');
        var popup = null;
        var customData = null;
        var oldOnBeforeUnload = null;
        var ignoreOnBeforeUnload = false;

        loadDialog();

        function loadDialog() {
            if (options.content) {
                showDialog({js: '', html: options.content});
                return;
            }
            $.ajax({
                type: options.method,
                url: options.url,
                data: $.isFunction(options.data) ? options.data() : options.data,
                cache: false, // IE caches GET AJAX requests. WTF.
                complete: IndicoUI.Dialogs.Util.progress(),
                error: function(xhr) {
                    var handled = false;
                    if (options.onLoadError && options.onLoadError(xhr) === false) {
                        handled = true;
                    }
                    if (options.trigger) {
                        var evt = $.Event('ajaxDialog:loadError');
                        $(options.trigger).trigger(evt, [xhr]);
                        if (evt.isDefaultPrevented()) {
                            handled = true;
                        }
                    }
                    if (!handled) {
                        handleAjaxError(xhr);
                    }
                },
                success: function(data, _, xhr) {
                    if (handleAjaxError(data)) {
                        return;
                    }
                    var loadedURL = xhr.getResponseHeader('X-Indico-URL');
                    if (loadedURL) {
                        // in case of a redirect we need to update the url used to submit the ajaxified
                        // form. otherwise url normalization might fail during the POST requests.
                        // we also remove the _=\d+ cache buster since it's only relevant for the GET
                        // request and added there automatically
                        options.url = loadedURL.replace(/&_=\d+/, '').replace(/\?_=\d+$/, '').replace(/\?_=\d+&/, '?');
                    }
                    showDialog(data);
                }
            });
        }

        function hasChangedFields() {
            var forms = popup.contentContainer.find('form');
            return forms.length && !!forms.filter(function() {
                return $(this).data('fieldsChanged');
            }).length;
        }

        function confirmClose() {
            return hasChangedFields() ? confirmPrompt(confirmCloseMessage, $T('Unsaved changes')) : $.Deferred().resolve();
        }

        function showDialog(dialogData) {
            if (popup) {
                _doCloseDialog();
            }
            popup = new ExclusivePopup($.isFunction(options.title) ? options.title.call(options.trigger) : options.title, function() {
                closeDialog(null);
                return false;
            }, false, false);

            popup.draw = function() {
                if (options.trigger && $(options.trigger).closest('.event-locked').length) {
                    this.canvas.addClass('event-locked');
                }
                this.ExclusivePopup.prototype.draw.call(this, dialogData.html);
                if (options.subtitle) {
                    this.canvas.prepend($('<div>', {
                        class: 'dialog-subtitle',
                        text: options.subtitle
                    }));
                }
                if (options.closeButton !== undefined && options.closeButton !== false) {
                    var text = options.closeButton === true ? $T.gettext("Close") : options.closeButton;
                    this.contentContainer.append($('<button>', {
                        'class': 'i-button big right',
                        'type': 'button',
                        'text': text,
                        'data-button-back': ''
                    }));
                }
            };

            popup.postDraw = function() {
                ajaxifyForms();
                popup.canvas.on('ajaxDialog:setData', function(e, data) {
                    customData = data;
                });
                popup.canvas.on('ajaxDialog:close', function(e, data, submitted) {
                    closeDialog(data, submitted);
                });
                popup.canvas.on('ajaxDialog:reload', function() {
                    loadDialog();
                });
                injectJS(dialogData.js);
                _onOpen();
                _.defer(function() {
                    popup.canvas.focusFirstField();
                });

                return true;
            };

            var dialogClasses = _.union(['dialog-window', options.dialogClasses]);
            if (options.hidePageHeader) {
                dialogClasses.push('no-page-header');
            }
            popup.canvas.addClass(dialogClasses.join(' '));

            if (options.confirmCloseUnsaved) {
                oldOnBeforeUnload = window.onbeforeunload;
                window.onbeforeunload = function() {
                    if (popup.isopen && !ignoreOnBeforeUnload && hasChangedFields()) {
                        return confirmCloseMessage;
                    }
                };
            }

            popup.open();
        }

        function closeDialog(callbackData, submitted) {
            var confirmDeferred = (submitted || !options.confirmCloseUnsaved) ? $.Deferred().resolve() : confirmClose();
            confirmDeferred.done(function() {
                ignoreOnBeforeUnload = true;
                var onCloseResult = _onClose(callbackData);
                if (onCloseResult === false) {
                    ignoreOnBeforeUnload = false;
                    return;
                } else if (!onCloseResult || onCloseResult === true) {
                    onCloseResult = $.Deferred().resolve();
                }
                onCloseResult.then(function() {
                    _doCloseDialog();
                    if (options.trigger) {
                        $(options.trigger).trigger('ajaxDialog:closed', [callbackData, customData]);
                    }
                }, function() {
                    ignoreOnBeforeUnload = false;
                });
            });
        }

        function _doCloseDialog() {
            popup.close();
            if (options.confirmCloseUnsaved) {
                window.onbeforeunload = oldOnBeforeUnload;
            }
            popup = null;
        }

        function _onOpen() {
            if (options.fullyModal) {
                $('html, body').addClass('prevent-scrolling');
            }
            if (options.onOpen) {
                options.onOpen(popup);
            }
        }

        function _onClose(callbackData) {
            if (options.fullyModal) {
                $('html, body').removeClass('prevent-scrolling');
            }
            if (!options.onClose) {
                return $.Deferred().resolve();
            } else {
                return options.onClose(callbackData, customData);
            }
        }

        function ajaxifyForms() {
            var killProgress = null;
            popup.contentContainer.on('click', options.backSelector, function(e) {
                e.preventDefault();
                closeDialog();
            });
            var forms = popup.contentContainer.find('form');
            showFormErrors(popup.resultContainer);
            initForms(forms);
            forms.filter(':not([data-no-ajax])').each(function() {
                var $this = $(this);
                $this.on('ajaxForm:beforeSubmit', function() {
                    killProgress = IndicoUI.Dialogs.Util.progress();
                }).on('ajaxForm:error', function(e, xhr) {
                    if (killProgress) {
                        killProgress();
                    }
                    e.preventDefault();
                    if ($.isFunction(options.onError)) {
                        options.onError.call($this, xhr);
                    } else {
                        handleAjaxError(xhr);
                    }
                }).on('ajaxForm:success', function(e, data) {
                    if (killProgress) {
                        killProgress();
                    }
                    if (handleAjaxError(data)) {
                        return;
                    }

                    handleFlashes(data, options.clearFlashes, options.trigger ? $(options.trigger) : null);

                    if (data.close_dialog || data.success) {
                        closeDialog(data, true);
                        if (data.redirect) {
                            if (!data.redirect_no_loading) {
                                IndicoUI.Dialogs.Util.progress();
                            }
                            location.href = data.redirect;
                        }
                    } else if (data.html) {
                        popup.contentContainer.html(data.html);
                        ajaxifyForms();
                        injectJS(data.js);
                    }
                });
                // We often use forms with an empty action; those need to go to
                // their page and not the page that loaded the dialog!
                var action = $this.attr('action') || options.url;
                $this.ajaxForm({
                    url: action,
                    dataType: 'json',
                    data: options.getExtraData.call(this, options.trigger),
                    beforeSubmit: function() {
                        var evt = $.Event('ajaxForm:validateBeforeSubmit');
                        $this.trigger(evt);
                        if (evt.isDefaultPrevented()) {
                            return false;
                        }
                        $this.trigger('ajaxForm:beforeSubmit');
                    },
                    error: function(xhr) {
                        $this.trigger('ajaxForm:error', [xhr]);
                    },
                    success: function(data) {
                        $this.trigger('ajaxForm:success', [data]);
                    }
                });
            });
        }

        function injectJS(js) {
            if (js) {
                $('body').append(js);
            }
        }
    };
})(window, jQuery);
<|endoftext|>


<commit_before><commit_msg>Bugfix<commit_after><|endoftext|>


<commit_before>var addListeners, removeListeners;
var insertMode, commandMode, settings;

var numberMap = ")!@#$%^&*(";
var keyMap = {
  8:   "BS",
  9:   "Tab",
  13:  "Enter",
  27:  "Esc",
  32:  "Space",
  37:  "Left",
  38:  "Up",
  39:  "Right",
  40:  "Down",
  186: [";", ":"],
  188: [",", "<"],
  189: ["-", "_"],
  190: ["."], ">"],
  187: ["=", "+"],
  191: ["/", "?"],
  192: ["`", "~"],
  219: ["[", "{"],
  221: ["]", "}"]
};

fromKeyCode = function(e) {
  var keyCode  = e.which;
  var shiftKey = e.shiftKey;
  var convertedKey;
  if (/^F[0-9]+$/.test(e.keyIdentifier)) {
    return "<" + e.keyIdentifier + ">";
  }
  if (keyMap.hasOwnProperty(keyCode.toString())) {
    convertedKey = keyMap[keyCode.toString()];
    if (Array.isArray(convertedKey)) {
      if (!e.ctrlKey && !e.altKey && !e.metaKey) {
        convertedKey = convertedKey[(shiftKey ? 1 : 0)];
      } else convertedKey = convertedKey[0];
    } else {
      if (shiftKey) convertedKey = "S-" + convertedKey;
    }
  } else {
    if (keyCode >= 48 && keyCode <= 57) {
      if (shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
        convertedKey = numberMap[keyCode - 48];
      } else {
        convertedKey = String.fromCharCode(keyCode);
      }
    } else {
      convertedKey = String.fromCharCode(keyCode);
      if (!shiftKey)
        convertedKey = String.fromCharCode(keyCode).toLowerCase();
    }
  }

  var modifier = "";
  if (e.ctrlKey) modifier += "-C";
  if (e.altKey)  modifier += "-A";
  if (e.metaKey) modifier += "-M";

  if (modifier) {
    modifier = modifier.replace(/^-/, "");
    convertedKey = "<" + modifier + "-" +
      ((shiftKey && !keyMap.hasOwnProperty(keyCode)) ?
      "S-" : "") +
      (!keyMap.hasOwnProperty(keyCode) ? convertedKey.toLowerCase() : convertedKey) + ">";
  }

  if (/^S-/.test(convertedKey) || (!modifier && keyCode <= 40 && keyMap.hasOwnProperty(keyCode))) convertedKey = "<" + convertedKey + ">";
  return convertedKey;
};

keyDown = function(e) {

  if (e.which === 18 && Hints.active) {
    return Hints.changeFocus();
  }
  if (e.which === 17 || e.which === 16 || e.which === 91 || e.which === 123) {
    return false;
  }

  var asciiKey = fromKeyCode(e);
  var validMapping = Mappings.isValidMapping(asciiKey);
  var keyType = {
    arrow: /^<(Left|Right|Up|Down)>$/.test(asciiKey),
    modifier: /^<[ACM]/.test(asciiKey),
    escape: /^<(Esc|C-\[)>$/.test(asciiKey),
  };

  if (!commandMode && Mappings.actions.inputFocused && e.which === 9) {
    if (!document.activeElement.isInput() || !Mappings.actions.inputElements.length) {
      return Mappings.actions.inputFocused = false;
    }
    e.preventDefault();
    e.stopPropagation();
    Mappings.actions.inputElementsIndex = ((e.shiftKey ? -1 : 1) + Mappings.actions.inputElementsIndex).mod(Mappings.actions.inputElements.length);
    Mappings.actions.inputElements[Mappings.actions.inputElementsIndex].focus();
    if (Mappings.actions.inputElements[Mappings.actions.inputElementsIndex].getAttribute("readonly")) {
      Mappings.actions.inputElements[Mappings.actions.inputElementsIndex].select();
    }
    return;
  }

  if (Visual.caretModeActive || Visual.visualModeActive) {
    e.stopPropagation();
    Visual.selection = document.getSelection();
    if (e.which === 8) {
      e.preventDefault();
    }
    if (keyType.escape) {
      if (Visual.visualModeActive === false) {
        return Visual.exit();
      }
      Visual.visualModeActive = false;
      HUD.setMessage(" -- CARET -- ");
      Visual.collapse();
    }
    return Visual.action(asciiKey.replace(/^<BS>$/, "h").replace(/^<Space>$/, "l"));
  } else {

    if (!insertMode && !document.activeElement.isInput()) {
      if (Hints.active) e.stopPropagation();
      if (Mappings.convertToAction(asciiKey)) {
        e.preventDefault();
        e.stopPropagation();
      }
    }

  }

  if (!Object.prototype.hasOwnProperty("isVisible")) {
    return false;
  }

  var isInput = (document.activeElement.isInput() ||
                 insertMode ||
                 Mappings.actions.inputFocused);

  if (!isInput && e.which > 40 && e.which !== 91 && e.which !== 123 && e.which !== 191) {
    if ((Mappings.queue.length && Mappings.validMatch) || validMapping) {
      e.stopPropagation();
    }
    if (!commandMode && asciiKey !== "" && validMapping) {
      e.preventDefault();
    }
  }

  if (settings.insertmappings && document.activeElement.isInput() && !insertMode && !keyType.escape && asciiKey !== "") {
    Mappings.insertCommand(asciiKey, function() {
      e.preventDefault();
      if (document.activeElement.id === "cVim-command-bar-input" && Command.type !== "search") {
        Command.complete(Command.input.value);
      }
    });
  } else if (Hints.active && (keyType.escape || e.which <= 40)) {
    e.stopPropagation();
    e.preventDefault();
    return Hints.hideHints();
  } else if (!commandMode) {
    if (keyType.escape || (!isInput && (e.which === 32 || e.which === 13))) {
      if (insertMode && !document.activeElement.isInput()) {
        insertMode = false;
        HUD.hide();
      } else if (Find.matches.length) {
        Find.clear();
        HUD.hide();
      }
      Mappings.actions.inputFocused = false;
      if (Mappings.queue !== "") {
        e.preventDefault();
        Mappings.queue = "";
        Mappings.repeats  = "";
      }
      if (isInput) document.activeElement.blur();
    } else if (!isInput && keyType.arrow && validMapping) {
      e.preventDefault();
      Mappings.convertToAction(asciiKey);
    }
  } else if (keyType.escape) {
    Mappings.actions.inputFocused = false;
    if (Command.type === "search") {
      Find.clear();
      HUD.hide();
    }
    Command.hide();
  }

  if (commandMode && document.activeElement.id === "cVim-command-bar-input") {

    switch (asciiKey) {

      case "<BS>": // Backspace (Vim style)
        if (Command.input.value.length === 0) {
          Command.hide();
          e.preventDefault();
          break;
        }
        if (Command.type === "search") {
          Find.clear();
          setTimeout(function() {
            if (Command.input.value !== "" && Command.input.value.length > 2) {
              Find.highlight(document.body, Command.input.value);
            } else {
              HUD.hide();
            }
          }, 0);
        } else {
          setTimeout(function() {
            Command.complete(Command.input.value);
          }, 0);
        }
        break;

      case "<Tab>":
      case "<S-Tab>":
        if (Command.type === "action") {
          e.preventDefault();
          Search.nextResult(e.shiftKey);
        }
        break;

      case "<Up>":
      case "<Down>":
        e.preventDefault();
        Command.history.cycle(Command.type, (asciiKey === "<Up>"));
        break;

      case "<Enter>":
      case "<C-Enter>":
        if (!/^(action|search)$/.test(Command.type)) {
          break;
        }
        e.preventDefault();
        if (!(Command.history[Command.type].length > 0 && Command.history[Command.type].slice(-1)[0] === Command.input.value)) {
          Command.history[Command.type].push(Command.input.value);
          chrome.runtime.sendMessage({action: "appendHistory", value: Command.input.value, type: Command.type});
        }
        document.activeElement.blur();
        if (Command.type === "search") {
          if (Command.input.value !== "" && (Command.input.value !== Find.lastSearch || Find.matches.length === 0)) {
            Find.clear();
            Find.highlight(document.body, Command.input.value, false, false, false, true);
          }
          setTimeout(function() {
            Find.index = -1;
            Find.setIndex();
            Find.search(false, 1);
            Command.hide();
          }, 0);
        } else {
          Command.execute(Command.input.value + (e.ctrlKey ? "&" : ""), 1);
        }
        break;

      default:
        Command.history.reset = true;
        if (Command.type === "action") {
          setTimeout(function() {
            Command.complete(Command.input.value);
          }, 0);
        } else {
          setTimeout(function() {
            if (Command.type === "search" && Command.input.value !== Find.lastSearch) {
              if (Command.input.value !== "") {
                Find.clear();
                if (Command.input.value.length > 2) {
                  Find.highlight(document.body, Command.input.value);
                }
              }
            }
          }, 2);
        }
        break;
    }

  }

};

var Mouse = {};
mouseMove = function(e) {
  Mouse.x = e.pageX;
  Mouse.y = e.pageY;
};

keyUp = function(e) {
  if (!insertMode) {
    e.stopPropagation();
    e.preventDefault();
  }
};

keyPress = function(e) {
  if (Visual.caretModeActive || Visual.visualModeActive) {
    e.preventDefault();
    e.stopPropagation();
  }
};

addListeners = function() {
  document.addEventListener("keypress", keyPress, true);
  document.addEventListener("keyup", keyUp, true);
  document.addEventListener("keydown", keyDown, true);
  document.addEventListener("mousemove", mouseMove, true);
};

removeListeners = function() {
  document.removeEventListener("keypress", keyPress, true);
  document.removeEventListener("keyup", keyUp, true);
  document.removeEventListener("keydown", keyDown, true);
  document.removeEventListener("mousemove", mouseMove, true);
};

chrome.extension.onMessage.addListener(function(request, callback) {
  switch (request.action) {
    case "toggleEnabled":
      Command.init(request.state);
      break;
    case "getBlacklistStatus":
      callback(Command.blacklisted);
      break;
  }
});
<commit_msg>Update keys.js<commit_after>var addListeners, removeListeners;
var insertMode, commandMode, settings;

var numberMap = ")!@#$%^&*(";
var keyMap = {
  8:   "BS",
  9:   "Tab",
  13:  "Enter",
  27:  "Esc",
  32:  "Space",
  37:  "Left",
  38:  "Up",
  39:  "Right",
  40:  "Down",
  186: [";", ":"],
  188: [",", "<"],
  189: ["-", "_"],
  190: [".", ">"],
  187: ["=", "+"],
  191: ["/", "?"],
  192: ["`", "~"],
  219: ["[", "{"],
  221: ["]", "}"]
};

fromKeyCode = function(e) {
  var keyCode  = e.which;
  var shiftKey = e.shiftKey;
  var convertedKey;
  if (/^F[0-9]+$/.test(e.keyIdentifier)) {
    return "<" + e.keyIdentifier + ">";
  }
  if (keyMap.hasOwnProperty(keyCode.toString())) {
    convertedKey = keyMap[keyCode.toString()];
    if (Array.isArray(convertedKey)) {
      if (!e.ctrlKey && !e.altKey && !e.metaKey) {
        convertedKey = convertedKey[(shiftKey ? 1 : 0)];
      } else convertedKey = convertedKey[0];
    } else {
      if (shiftKey) convertedKey = "S-" + convertedKey;
    }
  } else {
    if (keyCode >= 48 && keyCode <= 57) {
      if (shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
        convertedKey = numberMap[keyCode - 48];
      } else {
        convertedKey = String.fromCharCode(keyCode);
      }
    } else {
      convertedKey = String.fromCharCode(keyCode);
      if (!shiftKey)
        convertedKey = String.fromCharCode(keyCode).toLowerCase();
    }
  }

  var modifier = "";
  if (e.ctrlKey) modifier += "-C";
  if (e.altKey)  modifier += "-A";
  if (e.metaKey) modifier += "-M";

  if (modifier) {
    modifier = modifier.replace(/^-/, "");
    convertedKey = "<" + modifier + "-" +
      ((shiftKey && !keyMap.hasOwnProperty(keyCode)) ?
      "S-" : "") +
      (!keyMap.hasOwnProperty(keyCode) ? convertedKey.toLowerCase() : convertedKey) + ">";
  }

  if (/^S-/.test(convertedKey) || (!modifier && keyCode <= 40 && keyMap.hasOwnProperty(keyCode))) convertedKey = "<" + convertedKey + ">";
  return convertedKey;
};

keyDown = function(e) {

  if (e.which === 18 && Hints.active) {
    return Hints.changeFocus();
  }
  if (e.which === 17 || e.which === 16 || e.which === 91 || e.which === 123) {
    return false;
  }

  var asciiKey = fromKeyCode(e);
  var validMapping = Mappings.isValidMapping(asciiKey);
  var keyType = {
    arrow: /^<(Left|Right|Up|Down)>$/.test(asciiKey),
    modifier: /^<[ACM]/.test(asciiKey),
    escape: /^<(Esc|C-\[)>$/.test(asciiKey),
  };

  if (!commandMode && Mappings.actions.inputFocused && e.which === 9) {
    if (!document.activeElement.isInput() || !Mappings.actions.inputElements.length) {
      return Mappings.actions.inputFocused = false;
    }
    e.preventDefault();
    e.stopPropagation();
    Mappings.actions.inputElementsIndex = ((e.shiftKey ? -1 : 1) + Mappings.actions.inputElementsIndex).mod(Mappings.actions.inputElements.length);
    Mappings.actions.inputElements[Mappings.actions.inputElementsIndex].focus();
    if (Mappings.actions.inputElements[Mappings.actions.inputElementsIndex].getAttribute("readonly")) {
      Mappings.actions.inputElements[Mappings.actions.inputElementsIndex].select();
    }
    return;
  }

  if (Visual.caretModeActive || Visual.visualModeActive) {
    e.stopPropagation();
    Visual.selection = document.getSelection();
    if (e.which === 8) {
      e.preventDefault();
    }
    if (keyType.escape) {
      if (Visual.visualModeActive === false) {
        return Visual.exit();
      }
      Visual.visualModeActive = false;
      HUD.setMessage(" -- CARET -- ");
      Visual.collapse();
    }
    return Visual.action(asciiKey.replace(/^<BS>$/, "h").replace(/^<Space>$/, "l"));
  } else {

    if (!insertMode && !document.activeElement.isInput()) {
      if (Hints.active) e.stopPropagation();
      if (Mappings.convertToAction(asciiKey)) {
        e.preventDefault();
        e.stopPropagation();
      }
    }

  }

  if (!Object.prototype.hasOwnProperty("isVisible")) {
    return false;
  }

  var isInput = (document.activeElement.isInput() ||
                 insertMode ||
                 Mappings.actions.inputFocused);

  if (!isInput && e.which > 40 && e.which !== 91 && e.which !== 123 && e.which !== 191) {
    if ((Mappings.queue.length && Mappings.validMatch) || validMapping) {
      e.stopPropagation();
    }
    if (!commandMode && asciiKey !== "" && validMapping) {
      e.preventDefault();
    }
  }

  if (settings.insertmappings && document.activeElement.isInput() && !insertMode && !keyType.escape && asciiKey !== "") {
    Mappings.insertCommand(asciiKey, function() {
      e.preventDefault();
      if (document.activeElement.id === "cVim-command-bar-input" && Command.type !== "search") {
        Command.complete(Command.input.value);
      }
    });
  } else if (Hints.active && (keyType.escape || e.which <= 40)) {
    e.stopPropagation();
    e.preventDefault();
    return Hints.hideHints();
  } else if (!commandMode) {
    if (keyType.escape || (!isInput && (e.which === 32 || e.which === 13))) {
      if (insertMode && !document.activeElement.isInput()) {
        insertMode = false;
        HUD.hide();
      } else if (Find.matches.length) {
        Find.clear();
        HUD.hide();
      }
      Mappings.actions.inputFocused = false;
      if (Mappings.queue !== "") {
        e.preventDefault();
        Mappings.queue = "";
        Mappings.repeats  = "";
      }
      if (isInput) document.activeElement.blur();
    } else if (!isInput && keyType.arrow && validMapping) {
      e.preventDefault();
      Mappings.convertToAction(asciiKey);
    }
  } else if (keyType.escape) {
    Mappings.actions.inputFocused = false;
    if (Command.type === "search") {
      Find.clear();
      HUD.hide();
    }
    Command.hide();
  }

  if (commandMode && document.activeElement.id === "cVim-command-bar-input") {

    switch (asciiKey) {

      case "<BS>": // Backspace (Vim style)
        if (Command.input.value.length === 0) {
          Command.hide();
          e.preventDefault();
          break;
        }
        if (Command.type === "search") {
          Find.clear();
          setTimeout(function() {
            if (Command.input.value !== "" && Command.input.value.length > 2) {
              Find.highlight(document.body, Command.input.value);
            } else {
              HUD.hide();
            }
          }, 0);
        } else {
          setTimeout(function() {
            Command.complete(Command.input.value);
          }, 0);
        }
        break;

      case "<Tab>":
      case "<S-Tab>":
        if (Command.type === "action") {
          e.preventDefault();
          Search.nextResult(e.shiftKey);
        }
        break;

      case "<Up>":
      case "<Down>":
        e.preventDefault();
        Command.history.cycle(Command.type, (asciiKey === "<Up>"));
        break;

      case "<Enter>":
      case "<C-Enter>":
        if (!/^(action|search)$/.test(Command.type)) {
          break;
        }
        e.preventDefault();
        if (!(Command.history[Command.type].length > 0 && Command.history[Command.type].slice(-1)[0] === Command.input.value)) {
          Command.history[Command.type].push(Command.input.value);
          chrome.runtime.sendMessage({action: "appendHistory", value: Command.input.value, type: Command.type});
        }
        document.activeElement.blur();
        if (Command.type === "search") {
          if (Command.input.value !== "" && (Command.input.value !== Find.lastSearch || Find.matches.length === 0)) {
            Find.clear();
            Find.highlight(document.body, Command.input.value, false, false, false, true);
          }
          setTimeout(function() {
            Find.index = -1;
            Find.setIndex();
            Find.search(false, 1);
            Command.hide();
          }, 0);
        } else {
          Command.execute(Command.input.value + (e.ctrlKey ? "&" : ""), 1);
        }
        break;

      default:
        Command.history.reset = true;
        if (Command.type === "action") {
          setTimeout(function() {
            Command.complete(Command.input.value);
          }, 0);
        } else {
          setTimeout(function() {
            if (Command.type === "search" && Command.input.value !== Find.lastSearch) {
              if (Command.input.value !== "") {
                Find.clear();
                if (Command.input.value.length > 2) {
                  Find.highlight(document.body, Command.input.value);
                }
              }
            }
          }, 2);
        }
        break;
    }

  }

};

var Mouse = {};
mouseMove = function(e) {
  Mouse.x = e.pageX;
  Mouse.y = e.pageY;
};

keyUp = function(e) {
  if (!insertMode) {
    e.stopPropagation();
    e.preventDefault();
  }
};

keyPress = function(e) {
  if (Visual.caretModeActive || Visual.visualModeActive) {
    e.preventDefault();
    e.stopPropagation();
  }
};

addListeners = function() {
  document.addEventListener("keypress", keyPress, true);
  document.addEventListener("keyup", keyUp, true);
  document.addEventListener("keydown", keyDown, true);
  document.addEventListener("mousemove", mouseMove, true);
};

removeListeners = function() {
  document.removeEventListener("keypress", keyPress, true);
  document.removeEventListener("keyup", keyUp, true);
  document.removeEventListener("keydown", keyDown, true);
  document.removeEventListener("mousemove", mouseMove, true);
};

chrome.extension.onMessage.addListener(function(request, callback) {
  switch (request.action) {
    case "toggleEnabled":
      Command.init(request.state);
      break;
    case "getBlacklistStatus":
      callback(Command.blacklisted);
      break;
  }
});
<|endoftext|>


<commit_before>__indent = Array(mongo_hacker_config.indent + 1).join(' ');
__colorize = (_isWindows() && !mongo_hacker_config['force_color']) ? false : true;

ObjectId.prototype.toString = function() {
    return this.str;
};

ObjectId.prototype.tojson = function(indent, nolint) {
    return tojson(this);
};

var dateToJson = Date.prototype.tojson;

Date.prototype.tojson = function(indent, nolint, nocolor) {
  var isoDateString = dateToJson.call(this);
  var dateString = isoDateString.substring(8, isoDateString.length-1);

  var isodate = colorize(dateString, mongo_hacker_config.colors.date, nocolor);
  return 'ISODate(' + isodate + ')';
};

Array.tojson = function( a , indent , nolint, nocolor ){
    var lineEnding = nolint ? " " : "\n";

    if (!indent)
        indent = "";

    if ( nolint )
        indent = "";

    if (a.length === 0) {
        return "[ ]";
    }

    var s = "[" + lineEnding;
    indent += __indent;
    for ( var i=0; i<a.length; i++){
        s += indent + tojson( a[i], indent , nolint, nocolor );
        if ( i < a.length - 1 ){
            s += "," + lineEnding;
        }
    }
    if ( a.length === 0 ) {
        s += indent;
    }

    indent = indent.substring(__indent.length);
    s += lineEnding+indent+"]";
    return s;
};

function surround(name, inside) {
    return [name, '(', inside, ')'].join('');
}

Number.prototype.commify = function() {
    // http://stackoverflow.com/questions/2901102
    return this.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};

NumberLong.prototype.tojson = function(indent, nolint, nocolor) {
    var color = mongo_hacker_config.colors.number;
    var output = colorize('"' + this.toString().match(/-?\d+/)[0] + '"', color, nocolor);
    return surround('NumberLong', output);
};

NumberInt.prototype.tojson = function(indent, nolint, nocolor) {
    var color = mongo_hacker_config.colors.number;
    var output = colorize('"' + this.toString().match(/-?\d+/)[0] + '"', color, nocolor);
    return surround('NumberInt', output);
};

BinData.prototype.tojson = function(indent , nolint, nocolor) {
    var uuidType = mongo_hacker_config.uuid_type;
    var uuidColor = mongo_hacker_config.colors.uuid;
    var binDataColor = mongo_hacker_config.colors.binData;

    if (this.subtype() === 3) {
        var output = colorize('"' + uuidToString(this) + '"', uuidColor, nocolor) + ', '
        output += colorize('"' + uuidType + '"', uuidColor)
        return surround('UUID', output);
    } else if (this.subtype() === 4) {
        var output = colorize('"' + uuidToString(this, "default") + '"', uuidColor, nocolor) + ')'
        return surround('UUID', output);
    } else {
        var output = colorize(this.subtype(), {color: 'red'}) + ', '
        output += colorize('"' + this.base64() + '"', binDataColor, nocolor)
        return surround('BinData', output);
    }
};

DBQuery.prototype.shellPrint = function(){
    try {
        var start = new Date().getTime();
        var n = 0;
        while ( this.hasNext() && n < DBQuery.shellBatchSize ){
            var s = this._prettyShell ? tojson( this.next() ) : tojson( this.next() , "" , true );
            print( s );
            n++;
        }

        var output = [];

        if (typeof _verboseShell !== 'undefined' && _verboseShell) {
            var time = new Date().getTime() - start;
            var slowms = getSlowms();
            var fetched = "Fetched " + n + " record(s) in ";
            if (time > slowms) {
                fetched += colorize(time + "ms", { color: "red", bright: true });
            } else {
                fetched += colorize(time + "ms", { color: "green", bright: true });
            }
            output.push(fetched);
        }

        var paranoia = mongo_hacker_config.index_paranoia;

        if (typeof paranoia !== 'undefined' && paranoia) {
            var explain = this.clone();
            explain._ensureSpecial();
            explain._query.$explain = true;
            explain._limit = Math.abs(n) * -1;
            var result = explain.next();

            if (current_version < 3) {
                var type = result.cursor;

                if (type !== undefined) {
                    var index_use = "Index[";
                    if (type == "BasicCursor") {
                        index_use += colorize( "none", { color: "red", bright: true });
                    } else {
                        index_use += colorize( result.cursor.substring(12), { color: "green", bright: true });
                    }
                    index_use += "]";
                    output.push(index_use);
                }
            } else {
                var winningPlan = result.queryPlanner.winningPlan;
                var winningInputStage = winningPlan.inputStage.inputStage;

                if (winningPlan !== undefined) {
                    var index_use = "Index[";
                    if (winningPlan.inputStage.stage === "COLLSCAN" || (winningInputStage !== undefined && winningInputStage.stage !== "IXSCAN")) {
                        index_use += colorize( "none", { color: "red", bright: true });
                    } else {
                        var fullScan = false;
                        for (index in winningInputStage.keyPattern) {
                            if (winningInputStage.indexBounds[index][0] == "[MinKey, MaxKey]") {
                                fullScan = true;
                            }
                        }

                        if (fullScan) {
                            index_use += colorize( winningInputStage.indexName + " (full scan)", { color: "yellow", bright: true });
                        } else {
                            index_use += colorize( winningInputStage.indexName, { color: "green", bright: true });
                        }
                    }
                    index_use += "]";
                    output.push(index_use);
                }
            }
        }

        if ( this.hasNext() ) {
            ___it___  = this;
            output.push("More[" + colorize("true", { color: "green", bright: true }) + "]");
        }
        print(output.join(" -- "));
    }
    catch ( e ){
        print( e );
    }
};

function isInArray(array, value) {
    return array.indexOf(value) > -1;
}

tojsonObject = function( x, indent, nolint, nocolor, sort_keys ) {
    var lineEnding = nolint ? " " : "\n";
    var tabSpace = nolint ? "" : __indent;
    var sortKeys = (null == sort_keys) ? mongo_hacker_config.sort_keys : sort_keys;

    assert.eq( ( typeof x ) , "object" , "tojsonObject needs object, not [" + ( typeof x ) + "]" );

    if (!indent)
        indent = "";

    if ( typeof( x.tojson ) == "function" && x.tojson != tojson ) {
        return x.tojson( indent, nolint, nocolor );
    }

    if ( x.constructor && typeof( x.constructor.tojson ) == "function" && x.constructor.tojson != tojson ) {
        return x.constructor.tojson( x, indent , nolint, nocolor );
    }

    if ( x.toString() == "[object MaxKey]" )
        return "{ $maxKey : 1 }";
    if ( x.toString() == "[object MinKey]" )
        return "{ $minKey : 1 }";

    var s = "{" + lineEnding;

    // push one level of indent
    indent += tabSpace;

    var total = 0;
    for ( var k in x ) total++;
    if ( total === 0 ) {
        s += indent + lineEnding;
    }

    var keys = x;
    if ( typeof( x._simpleKeys ) == "function" )
        keys = x._simpleKeys();
    var num = 1;

    var keylist=[];

    for(var key in keys)
        keylist.push(key);

    if ( sortKeys ) {
        // Disable sorting if this object looks like an index spec
        if ( (isInArray(keylist, "v") && isInArray(keylist, "key") && isInArray(keylist, "name") && isInArray(keylist, "ns")) ) {
            sortKeys = false;
        } else {
            keylist.sort();
        }
    }

    for ( var i=0; i<keylist.length; i++) {
        var key=keylist[i];

        var val = x[key];
        if ( val == DB.prototype || val == DBCollection.prototype )
            continue;

        var color = mongo_hacker_config.colors.key;
        s += indent + colorize("\"" + key + "\"", color, nocolor) + ": " + tojson( val, indent , nolint, nocolor, sortKeys );
        if (num != total) {
            s += ",";
            num++;
        }
        s += lineEnding;
    }

    // pop one level of indent
    indent = indent.substring(__indent.length);
    return s + indent + "}";
};

tojson = function( x, indent , nolint, nocolor, sort_keys ) {

    var sortKeys = (null == sort_keys) ? mongo_hacker_config.sort_keys : sort_keys;

    if ( x === null )
        return colorize("null", mongo_hacker_config.colors['null'], nocolor);

    if ( x === undefined )
        return colorize("undefined", mongo_hacker_config.colors['undefined'], nocolor);

    if ( x.isObjectId ) {
        var color = mongo_hacker_config.colors['objectid'];
        return surround('ObjectId', colorize('"' + x.str + '"', color, nocolor));
    }

    if (!indent)
        indent = "";

    var s;
    switch ( typeof x ) {
    case "string": {
        s = "\"";
        for ( var i=0; i<x.length; i++ ){
            switch (x[i]){
                case '"': s += '\\"'; break;
                case '\\': s += '\\\\'; break;
                case '\b': s += '\\b'; break;
                case '\f': s += '\\f'; break;
                case '\n': s += '\\n'; break;
                case '\r': s += '\\r'; break;
                case '\t': s += '\\t'; break;

                default: {
                    var code = x.charCodeAt(i);
                    if (code < 0x20){
                        s += (code < 0x10 ? '\\u000' : '\\u00') + code.toString(16);
                    } else {
                        s += x[i];
                    }
                }
            }
        }
        s += "\"";
        return colorize(s, mongo_hacker_config.colors.string, nocolor);
    }
    case "number":
        return colorize(x, mongo_hacker_config.colors.number, nocolor);
    case "boolean":
        return colorize("" + x, mongo_hacker_config.colors['boolean'], nocolor);
    case "object": {
        s = tojsonObject( x, indent , nolint, nocolor, sortKeys );
        if ( ( nolint === null || nolint === true ) && s.length < 80 && ( indent === null || indent.length === 0 ) ){
            s = s.replace( /[\s\r\n ]+/gm , " " );
        }
        return s;
    }
    case "function":
        return colorize(x.toString(), mongo_hacker_config.colors['function'], nocolor);
    default:
        throw "tojson can't handle type " + ( typeof x );
    }

};

DBQuery.prototype._validate = function( o ){
    var firstKey = null;
    for (var k in o) { firstKey = k; break; }

    if (firstKey !== null && firstKey[0] == '$') {
        // for mods we only validate partially, for example keys may have dots
        this._validateObject( o );
    } else {
        // we're basically inserting a brand new object, do full validation
        this._validateForStorage( o );
    }
};

DBQuery.prototype._validateObject = function( o ){
    if (typeof(o) != "object")
        throw "attempted to save a " + typeof(o) + " value.  document expected.";

    if ( o._ensureSpecial && o._checkModify )
        throw "can't save a DBQuery object";
};

DBQuery.prototype._validateForStorage = function( o ){
    this._validateObject( o );
    for ( var k in o ){
        if ( k.indexOf( "." ) >= 0 ) {
            throw "can't have . in field names [" + k + "]" ;
        }

        if ( k.indexOf( "$" ) === 0 && ! DBCollection._allowedFields[k] ) {
            throw "field names cannot start with $ [" + k + "]";
        }

        if ( o[k] !== null && typeof( o[k] ) === "object" ) {
            this._validateForStorage( o[k] );
        }
    }
};

DBQuery.prototype._checkMulti = function(){
  if(this._limit > 0 || this._skip > 0){
    var ids = this.clone().select({_id: 1}).map(function(o){return o._id;});
    this._query['_id'] = {'$in': ids};
    return true;
  } else {
    return false;
  }
};

DBQuery.prototype.ugly = function(){
    this._prettyShell = false;
    return this;
}

DB.prototype.shutdownServer = function(opts) {
    if( "admin" != this._name ){
        return "shutdown command only works with the admin database; try 'use admin'";
    }

    cmd = {"shutdown" : 1};
    opts = opts || {};
    for (var o in opts) {
        cmd[o] = opts[o];
    }

    try {
        var res = this.runCommand(cmd);
        if( res )
            throw "shutdownServer failed: " + res.errmsg;
        throw "shutdownServer failed";
    }
    catch ( e ){
        assert( e.message.indexOf( "error doing query: failed" ) >= 0 , "unexpected error: " + tojson( e ) );
        print( "server should be down..." );
    }
}
<commit_msg>Remove extra parenthesis from UUID formatting<commit_after>__indent = Array(mongo_hacker_config.indent + 1).join(' ');
__colorize = (_isWindows() && !mongo_hacker_config['force_color']) ? false : true;

ObjectId.prototype.toString = function() {
    return this.str;
};

ObjectId.prototype.tojson = function(indent, nolint) {
    return tojson(this);
};

var dateToJson = Date.prototype.tojson;

Date.prototype.tojson = function(indent, nolint, nocolor) {
  var isoDateString = dateToJson.call(this);
  var dateString = isoDateString.substring(8, isoDateString.length-1);

  var isodate = colorize(dateString, mongo_hacker_config.colors.date, nocolor);
  return 'ISODate(' + isodate + ')';
};

Array.tojson = function( a , indent , nolint, nocolor ){
    var lineEnding = nolint ? " " : "\n";

    if (!indent)
        indent = "";

    if ( nolint )
        indent = "";

    if (a.length === 0) {
        return "[ ]";
    }

    var s = "[" + lineEnding;
    indent += __indent;
    for ( var i=0; i<a.length; i++){
        s += indent + tojson( a[i], indent , nolint, nocolor );
        if ( i < a.length - 1 ){
            s += "," + lineEnding;
        }
    }
    if ( a.length === 0 ) {
        s += indent;
    }

    indent = indent.substring(__indent.length);
    s += lineEnding+indent+"]";
    return s;
};

function surround(name, inside) {
    return [name, '(', inside, ')'].join('');
}

Number.prototype.commify = function() {
    // http://stackoverflow.com/questions/2901102
    return this.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};

NumberLong.prototype.tojson = function(indent, nolint, nocolor) {
    var color = mongo_hacker_config.colors.number;
    var output = colorize('"' + this.toString().match(/-?\d+/)[0] + '"', color, nocolor);
    return surround('NumberLong', output);
};

NumberInt.prototype.tojson = function(indent, nolint, nocolor) {
    var color = mongo_hacker_config.colors.number;
    var output = colorize('"' + this.toString().match(/-?\d+/)[0] + '"', color, nocolor);
    return surround('NumberInt', output);
};

BinData.prototype.tojson = function(indent , nolint, nocolor) {
    var uuidType = mongo_hacker_config.uuid_type;
    var uuidColor = mongo_hacker_config.colors.uuid;
    var binDataColor = mongo_hacker_config.colors.binData;

    if (this.subtype() === 3) {
        var output = colorize('"' + uuidToString(this) + '"', uuidColor, nocolor) + ', '
        output += colorize('"' + uuidType + '"', uuidColor)
        return surround('UUID', output);
    } else if (this.subtype() === 4) {
        var output = colorize('"' + uuidToString(this, "default") + '"', uuidColor, nocolor)
        return surround('UUID', output);
    } else {
        var output = colorize(this.subtype(), {color: 'red'}) + ', '
        output += colorize('"' + this.base64() + '"', binDataColor, nocolor)
        return surround('BinData', output);
    }
};

DBQuery.prototype.shellPrint = function(){
    try {
        var start = new Date().getTime();
        var n = 0;
        while ( this.hasNext() && n < DBQuery.shellBatchSize ){
            var s = this._prettyShell ? tojson( this.next() ) : tojson( this.next() , "" , true );
            print( s );
            n++;
        }

        var output = [];

        if (typeof _verboseShell !== 'undefined' && _verboseShell) {
            var time = new Date().getTime() - start;
            var slowms = getSlowms();
            var fetched = "Fetched " + n + " record(s) in ";
            if (time > slowms) {
                fetched += colorize(time + "ms", { color: "red", bright: true });
            } else {
                fetched += colorize(time + "ms", { color: "green", bright: true });
            }
            output.push(fetched);
        }

        var paranoia = mongo_hacker_config.index_paranoia;

        if (typeof paranoia !== 'undefined' && paranoia) {
            var explain = this.clone();
            explain._ensureSpecial();
            explain._query.$explain = true;
            explain._limit = Math.abs(n) * -1;
            var result = explain.next();

            if (current_version < 3) {
                var type = result.cursor;

                if (type !== undefined) {
                    var index_use = "Index[";
                    if (type == "BasicCursor") {
                        index_use += colorize( "none", { color: "red", bright: true });
                    } else {
                        index_use += colorize( result.cursor.substring(12), { color: "green", bright: true });
                    }
                    index_use += "]";
                    output.push(index_use);
                }
            } else {
                var winningPlan = result.queryPlanner.winningPlan;
                var winningInputStage = winningPlan.inputStage.inputStage;

                if (winningPlan !== undefined) {
                    var index_use = "Index[";
                    if (winningPlan.inputStage.stage === "COLLSCAN" || (winningInputStage !== undefined && winningInputStage.stage !== "IXSCAN")) {
                        index_use += colorize( "none", { color: "red", bright: true });
                    } else {
                        var fullScan = false;
                        for (index in winningInputStage.keyPattern) {
                            if (winningInputStage.indexBounds[index][0] == "[MinKey, MaxKey]") {
                                fullScan = true;
                            }
                        }

                        if (fullScan) {
                            index_use += colorize( winningInputStage.indexName + " (full scan)", { color: "yellow", bright: true });
                        } else {
                            index_use += colorize( winningInputStage.indexName, { color: "green", bright: true });
                        }
                    }
                    index_use += "]";
                    output.push(index_use);
                }
            }
        }

        if ( this.hasNext() ) {
            ___it___  = this;
            output.push("More[" + colorize("true", { color: "green", bright: true }) + "]");
        }
        print(output.join(" -- "));
    }
    catch ( e ){
        print( e );
    }
};

function isInArray(array, value) {
    return array.indexOf(value) > -1;
}

tojsonObject = function( x, indent, nolint, nocolor, sort_keys ) {
    var lineEnding = nolint ? " " : "\n";
    var tabSpace = nolint ? "" : __indent;
    var sortKeys = (null == sort_keys) ? mongo_hacker_config.sort_keys : sort_keys;

    assert.eq( ( typeof x ) , "object" , "tojsonObject needs object, not [" + ( typeof x ) + "]" );

    if (!indent)
        indent = "";

    if ( typeof( x.tojson ) == "function" && x.tojson != tojson ) {
        return x.tojson( indent, nolint, nocolor );
    }

    if ( x.constructor && typeof( x.constructor.tojson ) == "function" && x.constructor.tojson != tojson ) {
        return x.constructor.tojson( x, indent , nolint, nocolor );
    }

    if ( x.toString() == "[object MaxKey]" )
        return "{ $maxKey : 1 }";
    if ( x.toString() == "[object MinKey]" )
        return "{ $minKey : 1 }";

    var s = "{" + lineEnding;

    // push one level of indent
    indent += tabSpace;

    var total = 0;
    for ( var k in x ) total++;
    if ( total === 0 ) {
        s += indent + lineEnding;
    }

    var keys = x;
    if ( typeof( x._simpleKeys ) == "function" )
        keys = x._simpleKeys();
    var num = 1;

    var keylist=[];

    for(var key in keys)
        keylist.push(key);

    if ( sortKeys ) {
        // Disable sorting if this object looks like an index spec
        if ( (isInArray(keylist, "v") && isInArray(keylist, "key") && isInArray(keylist, "name") && isInArray(keylist, "ns")) ) {
            sortKeys = false;
        } else {
            keylist.sort();
        }
    }

    for ( var i=0; i<keylist.length; i++) {
        var key=keylist[i];

        var val = x[key];
        if ( val == DB.prototype || val == DBCollection.prototype )
            continue;

        var color = mongo_hacker_config.colors.key;
        s += indent + colorize("\"" + key + "\"", color, nocolor) + ": " + tojson( val, indent , nolint, nocolor, sortKeys );
        if (num != total) {
            s += ",";
            num++;
        }
        s += lineEnding;
    }

    // pop one level of indent
    indent = indent.substring(__indent.length);
    return s + indent + "}";
};

tojson = function( x, indent , nolint, nocolor, sort_keys ) {

    var sortKeys = (null == sort_keys) ? mongo_hacker_config.sort_keys : sort_keys;

    if ( x === null )
        return colorize("null", mongo_hacker_config.colors['null'], nocolor);

    if ( x === undefined )
        return colorize("undefined", mongo_hacker_config.colors['undefined'], nocolor);

    if ( x.isObjectId ) {
        var color = mongo_hacker_config.colors['objectid'];
        return surround('ObjectId', colorize('"' + x.str + '"', color, nocolor));
    }

    if (!indent)
        indent = "";

    var s;
    switch ( typeof x ) {
    case "string": {
        s = "\"";
        for ( var i=0; i<x.length; i++ ){
            switch (x[i]){
                case '"': s += '\\"'; break;
                case '\\': s += '\\\\'; break;
                case '\b': s += '\\b'; break;
                case '\f': s += '\\f'; break;
                case '\n': s += '\\n'; break;
                case '\r': s += '\\r'; break;
                case '\t': s += '\\t'; break;

                default: {
                    var code = x.charCodeAt(i);
                    if (code < 0x20){
                        s += (code < 0x10 ? '\\u000' : '\\u00') + code.toString(16);
                    } else {
                        s += x[i];
                    }
                }
            }
        }
        s += "\"";
        return colorize(s, mongo_hacker_config.colors.string, nocolor);
    }
    case "number":
        return colorize(x, mongo_hacker_config.colors.number, nocolor);
    case "boolean":
        return colorize("" + x, mongo_hacker_config.colors['boolean'], nocolor);
    case "object": {
        s = tojsonObject( x, indent , nolint, nocolor, sortKeys );
        if ( ( nolint === null || nolint === true ) && s.length < 80 && ( indent === null || indent.length === 0 ) ){
            s = s.replace( /[\s\r\n ]+/gm , " " );
        }
        return s;
    }
    case "function":
        return colorize(x.toString(), mongo_hacker_config.colors['function'], nocolor);
    default:
        throw "tojson can't handle type " + ( typeof x );
    }

};

DBQuery.prototype._validate = function( o ){
    var firstKey = null;
    for (var k in o) { firstKey = k; break; }

    if (firstKey !== null && firstKey[0] == '$') {
        // for mods we only validate partially, for example keys may have dots
        this._validateObject( o );
    } else {
        // we're basically inserting a brand new object, do full validation
        this._validateForStorage( o );
    }
};

DBQuery.prototype._validateObject = function( o ){
    if (typeof(o) != "object")
        throw "attempted to save a " + typeof(o) + " value.  document expected.";

    if ( o._ensureSpecial && o._checkModify )
        throw "can't save a DBQuery object";
};

DBQuery.prototype._validateForStorage = function( o ){
    this._validateObject( o );
    for ( var k in o ){
        if ( k.indexOf( "." ) >= 0 ) {
            throw "can't have . in field names [" + k + "]" ;
        }

        if ( k.indexOf( "$" ) === 0 && ! DBCollection._allowedFields[k] ) {
            throw "field names cannot start with $ [" + k + "]";
        }

        if ( o[k] !== null && typeof( o[k] ) === "object" ) {
            this._validateForStorage( o[k] );
        }
    }
};

DBQuery.prototype._checkMulti = function(){
  if(this._limit > 0 || this._skip > 0){
    var ids = this.clone().select({_id: 1}).map(function(o){return o._id;});
    this._query['_id'] = {'$in': ids};
    return true;
  } else {
    return false;
  }
};

DBQuery.prototype.ugly = function(){
    this._prettyShell = false;
    return this;
}

DB.prototype.shutdownServer = function(opts) {
    if( "admin" != this._name ){
        return "shutdown command only works with the admin database; try 'use admin'";
    }

    cmd = {"shutdown" : 1};
    opts = opts || {};
    for (var o in opts) {
        cmd[o] = opts[o];
    }

    try {
        var res = this.runCommand(cmd);
        if( res )
            throw "shutdownServer failed: " + res.errmsg;
        throw "shutdownServer failed";
    }
    catch ( e ){
        assert( e.message.indexOf( "error doing query: failed" ) >= 0 , "unexpected error: " + tojson( e ) );
        print( "server should be down..." );
    }
}
<|endoftext|>


<commit_before>process.on('SIGTERM',function () {
  console.log('received SIGTERM');
  setTimeout(function () {
    console.log('Exiting after some time.');
    process.exit(0);
  }, 1000);
});

setInterval(function (){
  console.log('Heartbeat');
}, 100);

//run with: --killSignal
//forever --killSignal=SIGTERM -w start server.js
<commit_msg>[dist] Whitespace cdo.<commit_after>process.on('SIGTERM',function () {
  console.log('received SIGTERM');
  setTimeout(function () {
    console.log('Exiting after some time.');
    process.exit(0);
  }, 1000);
});

setInterval(function (){
  console.log('Heartbeat');
}, 100);

// run with: --killSignal
// forever --killSignal=SIGTERM -w start server.js<|endoftext|>