<commit_before>Arbiter.Controls.ControlPanel = (function(){
	var selectedFeature = null;

	var selectControl = null;

	var modifyControl = null;

	var insertControl = null;

	var controlPanelHelper = new Arbiter.ControlPanelHelper();

	var mode = Arbiter.ControlPanelHelper.prototype.CONTROLS.SELECT;

	var cancel = false;

	var oomCleared = true;

	var onFinishedInserting = null;

	var _endInsertMode = function(){

		if(Arbiter.Util.existsAndNotNull(insertControl)){
			insertControl.deactivate();

			insertControl = null;
		}
	};

	var _startInsertMode = function(layerId, _geometryType){

		var olLayer = Arbiter.Layers.getLayerById(
				layerId, Arbiter.Layers.type.WFS);

		var geometryType = Arbiter.Geometry.getGeometryType(layerId, _geometryType);

		var geometryTypeName = Arbiter.Geometry.getGeometryName(geometryType);

		var context = Arbiter.Controls.ControlPanel;

		var schema = Arbiter.getLayerSchemas()[layerId];

		if(schema === null || schema === undefined){
			throw "Arbiter.Controls.ControlPanel _startInsertMode - "
				"could not get schema for layer id '" + layerId + "'";
		}

		controlPanelHelper.set(0, layerId, controlPanelHelper.CONTROLS.INSERT, 0, geometryTypeName, null, function(){

			var map = Arbiter.Map.getMap();
			selectControl.deactivate();
			insertControl = new Arbiter.Controls.Insert(olLayer, map,
					geometryType, function(feature){

				if(Arbiter.Util.existsAndNotNull(feature)){

					if(geometryType === Arbiter.Geometry.type.MULTIPOINT
							|| geometryType === Arbiter.Geometry.type.MULTILINE
							|| geometryType === Arbiter.Geometry.type.MULTIPOLYGON){

						if(!Arbiter.Util.existsAndNotNull(feature.metadata)){
							feature.metadata = {};
						}

						feature.metadata[Arbiter.FeatureTableHelper.PART_OF_MULTI] = true;
					}

					_endInsertMode();

					mode = Arbiter.ControlPanelHelper.prototype.CONTROLS.INSERT;

					selectControl.activate();

					selectControl.select(feature);

					selectedFeature = feature;

					startModifyMode(feature, function(){
						if(Arbiter.Util.existsAndNotNull(onFinishedInserting)){

							onFinishedInserting();

							onFinishedInserting = null;
						}
					});
				}else{

					_endInsertMode();

					if(Arbiter.Util.existsAndNotNull(onFinishedInserting)){

						onFinishedInserting();

						onFinishedInserting = null;
					}
				}
			});
		}, function(e){
			console.log("start insert mode error", e.stack);
		});
	};

	var startModifyMode = function(feature, onStartedModifyMode){

		var featureId = null;

		if(Arbiter.Util.existsAndNotNull(feature.metadata)){
			featureId = feature.metadata[Arbiter.FeatureTableHelper.ID];
		}

		var layerId = Arbiter.Util.getLayerId(feature.layer);

		var geometryType = Arbiter.Geometry.getGeometryType(layerId);

		var geometryTypeName = Arbiter.Geometry.getGeometryName(geometryType);

		if(geometryType === Arbiter.Geometry.type.MULTIGEOMETRY && feature.geometry.CLASS_NAME !== "OpenLayers.Geometry.Collection"){

			var collection = new OpenLayers.Geometry.Collection([feature.geometry]);

			feature.geometry = collection;
		}

		var wktGeometry = Arbiter.Geometry.getNativeWKT(feature, layerId);

		var schema = Arbiter.getLayerSchemas()[layerId];

		modifyControl = new Arbiter.Controls.Modify(Arbiter.Map.getMap(),
				feature.layer, feature, schema);

		controlPanelHelper.set(featureId, layerId,
				controlPanelHelper.CONTROLS.MODIFY, wktGeometry, geometryTypeName, null, function(){

			selectControl.deactivate();

			modifyControl.activate();

			mode = Arbiter.ControlPanelHelper.prototype.CONTROLS.MODIFY;

			if(Arbiter.Util.funcExists(onStartedModifyMode)){
				onStartedModifyMode();
			}
		}, function(e){
			console.log("start modify mode error", e);
		});
	};

	var removeFeature = function(feature){
		var layer = feature.layer;

		layer.removeFeatures([feature]);
	};

	var onSelect = function(feature){
		console.log("feature selected and selectedFeature = ", selectedFeature, feature);

		console.log("controlPanel onSelect modifyControl is", modifyControl);

		selectedFeature = feature;

		if(Arbiter.Util.existsAndNotNull(feature.layer)
				// Account for the layers created by the draw feature control/handler
				&& (feature.layer.name.indexOf("OpenLayers") === -1)){

			var _mode = mode;
			var _cancel = cancel;

			// Make sure the mode related variables are reset
			mode = Arbiter.ControlPanelHelper.prototype.CONTROLS.SELECT;
			cancel = false;

			var featureId = null;

			if(Arbiter.Util.existsAndNotNull(feature.metadata)){
				featureId = feature.metadata[Arbiter.FeatureTableHelper.ID];
			}

			var layerId = Arbiter.Util.getLayerId(feature.layer);

			var exec = function(){
				if(Arbiter.Util.existsAndNotNull(selectedFeature.metadata) && selectedFeature.metadata["modified"]){
					delete selectedFeature.metadata["modified"];
				}else{
					Arbiter.Cordova.featureSelected(
							feature.layer.protocol.featureType,
							featureId,
							layerId,
							feature,
							_mode,
							_cancel
					);
				}
			};

			/*if(Arbiter.Util.existsAndNotNull(featureId)){

				controlPanelHelper.set(featureId, layerId, controlPanelHelper.CONTROLS.SELECT, 0, null, null, function(){

					oomCleared = false;

					exec();
				}, function(e){
					console.log("Error saving select mode", e);
				});
			}else{*/
				exec();
			//}
		}
	};

	var onUnselect = function(feature){

		console.log("feature unselected: ", feature);
		// Unselect all features (added for multigeometries)
		selectControl.unselect();

		// If the modifyControl is null,
		// make sure selectedFeature is
		// cleared out.
		if(modifyControl === null){
			selectedFeature = null;

			if(!oomCleared){
				// Starting to clear out so flag
				// it for already cleared
				oomCleared = true;

				controlPanelHelper.clear(function(){
					console.log("control panel cleared successfully");
					Arbiter.Cordova.featureUnselected();
				}, function(e){
					console.log("Couldn't clear the control panel...", e);
					oomCleared = false;
				});
			}
		}
	};

	selectControl = new Arbiter.Controls.Select(onSelect, onUnselect);

	return {
		registerMapListeners: function(){
			selectControl.registerMapListeners();
		},

		enterModifyMode: function(feature, onStartedModifyMode){
			try{
				if(feature === null
						|| feature === undefined){

					feature = selectedFeature;
				}

				if(feature === null || feature === undefined){
					throw "ControlPanel.js feature should not be " + feature;
				}

				startModifyMode(feature, onStartedModifyMode);
			}catch(e){
				console.log("enterModifyMode error", e);
			}
		},

		exitModifyMode: function(onExitModify){

			if(!Arbiter.Util.existsAndNotNull(modifyControl)){

				if(Arbiter.Util.existsAndNotNull(onExitModify)){
					onExitModify();
				}

				return;
			}

			modifyControl.done(function(){

				modifyControl = null;

				selectControl.activate();

				if(Arbiter.Util.existsAndNotNull(selectedFeature)){

					if(!Arbiter.Util.existsAndNotNull(selectedFeature.metadata)){
						selectedFeature.metadata = {};
					}

					selectedFeature.metadata["modified"] = true;

					selectControl.select(selectedFeature);
				}

				try{
					if(Arbiter.Util.existsAndNotNull(onExitModify)){
						onExitModify();
					}
				}catch(e){
					console.log(e.stack);
				}
			});
		},

		unselect: function(){
			console.log("ControlPanel.unselect()");
			selectControl.unselect();

			if(modifyControl === null){
				selectedFeature = null;

				controlPanelHelper.clear();
			}
		},

		/**
		 * Restore the geometry to its original location,
		 * and exit modify mode.
		 */
		cancelEdit: function(wktGeometry){
			console.log("ControlPanel.cancelEdit wktGeometry = " + wktGeometry);

			modifyControl.cancel(wktGeometry, function(){
				//modifyControl.deactivate();

				modifyControl = null;

				// Reactivate the selectControl
				selectControl.activate();

				//console.log("selectControl active: " + selectControl.isActive());

				if(!Arbiter.Util.existsAndNotNull(selectedFeature.metadata)){
					selectedFeature.metadata = {};
				}

				selectedFeature.metadata["modified"] = true;

				// Reselect the selectedFeature
				selectControl.select(selectedFeature);
			});
		},

		getSelectedFeature: function(){
			return selectedFeature;
		},

		startInsertMode: function(layerId, geometryType){

			_startInsertMode(layerId, geometryType);
		},

		finishGeometry: function(){
			if(Arbiter.Util.existsAndNotNull(insertControl)){
				insertControl.finishGeometry();
			}
		},

		finishInserting: function(_onFinishedInserting){

			if(Arbiter.Util.existsAndNotNull(insertControl)){

				onFinishedInserting = _onFinishedInserting;

				insertControl.finishInserting();
			}else{

				_onFinishedInserting();

				onFinishedInserting = null;
			}
		},

		getInsertControl: function(){
			return insertControl;
		},

		moveSelectedFeature: function(wktGeometry){

			if(wktGeometry === null || wktGeometry === undefined){
				throw "Arbiter.Controls.ControlPanel - couldn't restore original"
				+ " geometry because wktGeometry is " + wktGeometry;
			}

			if(selectedFeature === null || selectedFeature === undefined){
				throw "Arbiter.Controls.Select - couldn't restore original"
				+ " geometry because selectedFeature is " + selectedFeature;
			}

			var geomFeature = Arbiter.Geometry.readWKT(wktGeometry);

			var olLayer = selectedFeature.layer;

			var layerId = Arbiter.Util.getLayerId(olLayer);

			var schema = Arbiter.getLayerSchemas()[layerId];

			var srid = Arbiter.Map.getMap().projection.projCode;

			geomFeature.geometry.transform(new OpenLayers.Projection(schema.getSRID()),
					new OpenLayers.Projection(srid));

			olLayer.removeFeatures([selectedFeature]);

			selectedFeature.geometry = geomFeature.geometry;

			olLayer.addFeatures([selectedFeature]);
		},
		/**
		 * @param { OpenLayers.Feature.Vector } feature The feature to select.
		 */
		select: function(feature){
			selectControl.select(feature);
		},

		setSelectedFeature: function(feature){
			selectedFeature = feature;
		},

		setMode: function(_mode){
			mode = _mode;
		},

		getMode: function(){
			return mode;
		},

		getCancel: function(){
			return cancel;
		},

		isAddingPart: function(){

			if(Arbiter.Util.existsAndNotNull(modifyControl)){

				Arbiter.Cordova.isAddingGeometryPart(modifyControl.isAddingPart());
			}
		},

		addPart: function(){
			console.log("ControlPanel.addPart");

			modifyControl.beginAddPart();
		},

		removePart: function(){
			console.log("ControlPanel.removePart");

			modifyControl.removePart();
		},

		addGeometry: function(geometryType){
			console.log("ControlPanel.addGeometry: " + geometryType);

			modifyControl.beginAddGeometry(geometryType);
		},

		removeGeometry: function(){
			console.log("ControlPanel.removeGeometry");

			modifyControl.removeGeometry();
		},

		getModifyControl: function(){
			return modifyControl;
		},

		selectGeometryPartByIndexChain: function(indexChain){

			modifyControl.selectGeometryPartByIndexChain(indexChain);
		}
	};
})();<commit_msg>Uncommented this to temporarily "fix" the feature selecting issue<commit_after>Arbiter.Controls.ControlPanel = (function(){
	var selectedFeature = null;

	var selectControl = null;

	var modifyControl = null;

	var insertControl = null;

	var controlPanelHelper = new Arbiter.ControlPanelHelper();

	var mode = Arbiter.ControlPanelHelper.prototype.CONTROLS.SELECT;

	var cancel = false;

	var oomCleared = true;

	var onFinishedInserting = null;

	var _endInsertMode = function(){

		if(Arbiter.Util.existsAndNotNull(insertControl)){
			insertControl.deactivate();

			insertControl = null;
		}
	};

	var _startInsertMode = function(layerId, _geometryType){

		var olLayer = Arbiter.Layers.getLayerById(
				layerId, Arbiter.Layers.type.WFS);

		var geometryType = Arbiter.Geometry.getGeometryType(layerId, _geometryType);

		var geometryTypeName = Arbiter.Geometry.getGeometryName(geometryType);

		var context = Arbiter.Controls.ControlPanel;

		var schema = Arbiter.getLayerSchemas()[layerId];

		if(schema === null || schema === undefined){
			throw "Arbiter.Controls.ControlPanel _startInsertMode - "
				"could not get schema for layer id '" + layerId + "'";
		}

		controlPanelHelper.set(0, layerId, controlPanelHelper.CONTROLS.INSERT, 0, geometryTypeName, null, function(){

			var map = Arbiter.Map.getMap();
			selectControl.deactivate();
			insertControl = new Arbiter.Controls.Insert(olLayer, map,
					geometryType, function(feature){

				if(Arbiter.Util.existsAndNotNull(feature)){

					if(geometryType === Arbiter.Geometry.type.MULTIPOINT
							|| geometryType === Arbiter.Geometry.type.MULTILINE
							|| geometryType === Arbiter.Geometry.type.MULTIPOLYGON){

						if(!Arbiter.Util.existsAndNotNull(feature.metadata)){
							feature.metadata = {};
						}

						feature.metadata[Arbiter.FeatureTableHelper.PART_OF_MULTI] = true;
					}

					_endInsertMode();

					mode = Arbiter.ControlPanelHelper.prototype.CONTROLS.INSERT;

					selectControl.activate();

					selectControl.select(feature);

					selectedFeature = feature;

					startModifyMode(feature, function(){
						if(Arbiter.Util.existsAndNotNull(onFinishedInserting)){

							onFinishedInserting();

							onFinishedInserting = null;
						}
					});
				}else{

					_endInsertMode();

					if(Arbiter.Util.existsAndNotNull(onFinishedInserting)){

						onFinishedInserting();

						onFinishedInserting = null;
					}
				}
			});
		}, function(e){
			console.log("start insert mode error", e.stack);
		});
	};

	var startModifyMode = function(feature, onStartedModifyMode){

		var featureId = null;

		if(Arbiter.Util.existsAndNotNull(feature.metadata)){
			featureId = feature.metadata[Arbiter.FeatureTableHelper.ID];
		}

		var layerId = Arbiter.Util.getLayerId(feature.layer);

		var geometryType = Arbiter.Geometry.getGeometryType(layerId);

		var geometryTypeName = Arbiter.Geometry.getGeometryName(geometryType);

		if(geometryType === Arbiter.Geometry.type.MULTIGEOMETRY && feature.geometry.CLASS_NAME !== "OpenLayers.Geometry.Collection"){

			var collection = new OpenLayers.Geometry.Collection([feature.geometry]);

			feature.geometry = collection;
		}

		var wktGeometry = Arbiter.Geometry.getNativeWKT(feature, layerId);

		var schema = Arbiter.getLayerSchemas()[layerId];

		modifyControl = new Arbiter.Controls.Modify(Arbiter.Map.getMap(),
				feature.layer, feature, schema);

		controlPanelHelper.set(featureId, layerId,
				controlPanelHelper.CONTROLS.MODIFY, wktGeometry, geometryTypeName, null, function(){

			selectControl.deactivate();

			modifyControl.activate();

			mode = Arbiter.ControlPanelHelper.prototype.CONTROLS.MODIFY;

			if(Arbiter.Util.funcExists(onStartedModifyMode)){
				onStartedModifyMode();
			}
		}, function(e){
			console.log("start modify mode error", e);
		});
	};

	var removeFeature = function(feature){
		var layer = feature.layer;

		layer.removeFeatures([feature]);
	};

	var onSelect = function(feature){
		console.log("feature selected and selectedFeature = ", selectedFeature, feature);

		console.log("controlPanel onSelect modifyControl is", modifyControl);

		selectedFeature = feature;

		if(Arbiter.Util.existsAndNotNull(feature.layer)
				// Account for the layers created by the draw feature control/handler
				&& (feature.layer.name.indexOf("OpenLayers") === -1)){

			var _mode = mode;
			var _cancel = cancel;

			// Make sure the mode related variables are reset
			mode = Arbiter.ControlPanelHelper.prototype.CONTROLS.SELECT;
			cancel = false;

			var featureId = null;

			if(Arbiter.Util.existsAndNotNull(feature.metadata)){
				featureId = feature.metadata[Arbiter.FeatureTableHelper.ID];
			}

			var layerId = Arbiter.Util.getLayerId(feature.layer);

			var exec = function(){
				if(Arbiter.Util.existsAndNotNull(selectedFeature.metadata) && selectedFeature.metadata["modified"]){
					delete selectedFeature.metadata["modified"];
				}else{
					Arbiter.Cordova.featureSelected(
							feature.layer.protocol.featureType,
							featureId,
							layerId,
							feature,
							_mode,
							_cancel
					);
				}
			};

			if(Arbiter.Util.existsAndNotNull(featureId)){

				controlPanelHelper.set(featureId, layerId, controlPanelHelper.CONTROLS.SELECT, 0, null, null, function(){

					oomCleared = false;

					exec();
				}, function(e){
					console.log("Error saving select mode", e);
				});
			}else{
				exec();
			}
		}
	};

	var onUnselect = function(feature){

		console.log("feature unselected: ", feature);
		// Unselect all features (added for multigeometries)
		selectControl.unselect();

		// If the modifyControl is null,
		// make sure selectedFeature is
		// cleared out.
		if(modifyControl === null){
			selectedFeature = null;

			if(!oomCleared){
				// Starting to clear out so flag
				// it for already cleared
				oomCleared = true;

				controlPanelHelper.clear(function(){
					console.log("control panel cleared successfully");
					Arbiter.Cordova.featureUnselected();
				}, function(e){
					console.log("Couldn't clear the control panel...", e);
					oomCleared = false;
				});
			}
		}
	};

	selectControl = new Arbiter.Controls.Select(onSelect, onUnselect);

	return {
		registerMapListeners: function(){
			selectControl.registerMapListeners();
		},

		enterModifyMode: function(feature, onStartedModifyMode){
			try{
				if(feature === null
						|| feature === undefined){

					feature = selectedFeature;
				}

				if(feature === null || feature === undefined){
					throw "ControlPanel.js feature should not be " + feature;
				}

				startModifyMode(feature, onStartedModifyMode);
			}catch(e){
				console.log("enterModifyMode error", e);
			}
		},

		exitModifyMode: function(onExitModify){

			if(!Arbiter.Util.existsAndNotNull(modifyControl)){

				if(Arbiter.Util.existsAndNotNull(onExitModify)){
					onExitModify();
				}

				return;
			}

			modifyControl.done(function(){

				modifyControl = null;

				selectControl.activate();

				if(Arbiter.Util.existsAndNotNull(selectedFeature)){

					if(!Arbiter.Util.existsAndNotNull(selectedFeature.metadata)){
						selectedFeature.metadata = {};
					}

					selectedFeature.metadata["modified"] = true;

					selectControl.select(selectedFeature);
				}

				try{
					if(Arbiter.Util.existsAndNotNull(onExitModify)){
						onExitModify();
					}
				}catch(e){
					console.log(e.stack);
				}
			});
		},

		unselect: function(){
			console.log("ControlPanel.unselect()");
			selectControl.unselect();

			if(modifyControl === null){
				selectedFeature = null;

				controlPanelHelper.clear();
			}
		},

		/**
		 * Restore the geometry to its original location,
		 * and exit modify mode.
		 */
		cancelEdit: function(wktGeometry){
			console.log("ControlPanel.cancelEdit wktGeometry = " + wktGeometry);

			modifyControl.cancel(wktGeometry, function(){
				//modifyControl.deactivate();

				modifyControl = null;

				// Reactivate the selectControl
				selectControl.activate();

				//console.log("selectControl active: " + selectControl.isActive());

				if(!Arbiter.Util.existsAndNotNull(selectedFeature.metadata)){
					selectedFeature.metadata = {};
				}

				selectedFeature.metadata["modified"] = true;

				// Reselect the selectedFeature
				selectControl.select(selectedFeature);
			});
		},

		getSelectedFeature: function(){
			return selectedFeature;
		},

		startInsertMode: function(layerId, geometryType){

			_startInsertMode(layerId, geometryType);
		},

		finishGeometry: function(){
			if(Arbiter.Util.existsAndNotNull(insertControl)){
				insertControl.finishGeometry();
			}
		},

		finishInserting: function(_onFinishedInserting){

			if(Arbiter.Util.existsAndNotNull(insertControl)){

				onFinishedInserting = _onFinishedInserting;

				insertControl.finishInserting();
			}else{

				_onFinishedInserting();

				onFinishedInserting = null;
			}
		},

		getInsertControl: function(){
			return insertControl;
		},

		moveSelectedFeature: function(wktGeometry){

			if(wktGeometry === null || wktGeometry === undefined){
				throw "Arbiter.Controls.ControlPanel - couldn't restore original"
				+ " geometry because wktGeometry is " + wktGeometry;
			}

			if(selectedFeature === null || selectedFeature === undefined){
				throw "Arbiter.Controls.Select - couldn't restore original"
				+ " geometry because selectedFeature is " + selectedFeature;
			}

			var geomFeature = Arbiter.Geometry.readWKT(wktGeometry);

			var olLayer = selectedFeature.layer;

			var layerId = Arbiter.Util.getLayerId(olLayer);

			var schema = Arbiter.getLayerSchemas()[layerId];

			var srid = Arbiter.Map.getMap().projection.projCode;

			geomFeature.geometry.transform(new OpenLayers.Projection(schema.getSRID()),
					new OpenLayers.Projection(srid));

			olLayer.removeFeatures([selectedFeature]);

			selectedFeature.geometry = geomFeature.geometry;

			olLayer.addFeatures([selectedFeature]);
		},
		/**
		 * @param { OpenLayers.Feature.Vector } feature The feature to select.
		 */
		select: function(feature){
			selectControl.select(feature);
		},

		setSelectedFeature: function(feature){
			selectedFeature = feature;
		},

		setMode: function(_mode){
			mode = _mode;
		},

		getMode: function(){
			return mode;
		},

		getCancel: function(){
			return cancel;
		},

		isAddingPart: function(){

			if(Arbiter.Util.existsAndNotNull(modifyControl)){

				Arbiter.Cordova.isAddingGeometryPart(modifyControl.isAddingPart());
			}
		},

		addPart: function(){
			console.log("ControlPanel.addPart");

			modifyControl.beginAddPart();
		},

		removePart: function(){
			console.log("ControlPanel.removePart");

			modifyControl.removePart();
		},

		addGeometry: function(geometryType){
			console.log("ControlPanel.addGeometry: " + geometryType);

			modifyControl.beginAddGeometry(geometryType);
		},

		removeGeometry: function(){
			console.log("ControlPanel.removeGeometry");

			modifyControl.removeGeometry();
		},

		getModifyControl: function(){
			return modifyControl;
		},

		selectGeometryPartByIndexChain: function(indexChain){

			modifyControl.selectGeometryPartByIndexChain(indexChain);
		}
	};
})();<|endoftext|>


<commit_before>'use strict';

var fs            = require('fs');
var os            = require('os');
var path          = require('path');
var expect        = require('chai').expect;
var map           = require('lodash/map');
var MockUI        = require('../../helpers/mock-ui');
var MockAnalytics = require('../../helpers/mock-analytics');
var stub          = require('../../helpers/stub');
var Promise       = require('../../../lib/ext/promise');
var Blueprint     = require('../../../lib/models/blueprint');
var Project       = require('../../../lib/models/project');
var Task          = require('../../../lib/models/task');
var InitCommand   = require('../../../lib/commands/init');

var safeRestore = stub.safeRestore;
stub = stub.stub;

describe('init command', function() {
  var ui, analytics, tasks, command;

  beforeEach(function() {
    ui = new MockUI();
    analytics = new MockAnalytics();
    tasks = {
      InstallBlueprint: Task.extend({}),
      NpmInstall: Task.extend({}),
      BowerInstall: Task.extend({})
    };
  });

  afterEach(function() {
    safeRestore(Blueprint, 'lookup');
  });

  function buildCommand(projectOpts) {
    var options = {
      ui: ui,
      analytics: analytics,
      project: new Project(process.cwd(), projectOpts || { name: 'some-random-name' }),
      tasks: tasks,
      settings: {}
    };

    command = new InitCommand(options);
  }

  it('doesn\'t allow to create an application named `test`', function() {
    buildCommand({ name: 'test' });

    return command.validateAndRun([]).then(function() {
      expect(false, 'should have rejected with an application name of test').to.be.ok;
    })
    .catch(function(error) {
      expect(error.message).to.equal('We currently do not support a name of `test`.');
    });
  });

  it('doesn\'t allow to create an application without project name', function() {
    buildCommand({ name: undefined });

    return command.validateAndRun([]).then(function() {
      expect(false, 'should have rejected with an application without project name').to.be.ok;
    })
    .catch(function(error) {
      expect(error.message).to.equal('The `ember init` command requires a package.json in current folder with name attribute or a specified name via arguments. For more details, use `ember help`.');
    });
  });

  it('Uses the name of the closest project to when calling installBlueprint', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal('some-random-name');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun([])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses the provided app name over the closest found project', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal('provided-name');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['--name=provided-name'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses process.cwd if no package is found when calling installBlueprint', function() {
    // change the working dir so `process.cwd` can't be a invalid path for base directories
    // named `ember-cli`.

    var tmpDir = os.tmpdir();
    var workingDir = tmpDir + '/ember-cli-test-project';
    var currentWorkingDir = process.cwd();

    fs.mkdirSync(workingDir);
    process.chdir(workingDir);

    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal(path.basename(process.cwd()));
        return Promise.reject('Called run');
      }
    });

    buildCommand({ name: path.basename(process.cwd()) });

    return command.validateAndRun([])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      })
      .then(function() {
        process.chdir(currentWorkingDir);
        fs.rmdirSync(workingDir);
      });
  });

  it('doesn\'t use --dry-run or any other command option as the name', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal('some-random-name');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['--dry-run'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('doesn\'t use . as the name', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal('some-random-name');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['.'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses the "app" blueprint by default', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.blueprint).to.equal('app');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['--name=provided-name'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses arguments to select files to init', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.blueprint).to.equal('app');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['package.json', '--name=provided-name'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses the "addon" blueprint for addons', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.blueprint).to.equal('addon');
        return Promise.reject('Called run');
      }
    });

    buildCommand({ keywords: ['ember-addon'], name: 'some-random-name' });

    return command.validateAndRun(['--name=provided-name'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Registers blueprint options in beforeRun', function() {
    stub(Blueprint, 'lookup', function(name) {
      expect(name).to.equal('app');
      return {
        availableOptions: [
          { name: 'custom-blueprint-option', type: String }
        ]
      };
    }, true);

    buildCommand();

    command.beforeRun(['app']);
    expect(map(command.availableOptions, 'name')).to.contain('custom-blueprint-option');
  });

  it('Passes command options through to the install blueprint task', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts).to.contain.keys('customOption');
        expect(blueprintOpts.customOption).to.equal('customValue');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['--custom-option=customValue'])
      .then(function() {
        expect(false, 'promise should have rejected').to.be.ok;
      })
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });
});
<commit_msg>tests/commands/init: Use testdouble for mocks<commit_after>'use strict';

var fs            = require('fs');
var os            = require('os');
var path          = require('path');
var expect        = require('chai').expect;
var map           = require('lodash/map');
var MockUI        = require('../../helpers/mock-ui');
var MockAnalytics = require('../../helpers/mock-analytics');
var Promise       = require('../../../lib/ext/promise');
var Blueprint     = require('../../../lib/models/blueprint');
var Project       = require('../../../lib/models/project');
var Task          = require('../../../lib/models/task');
var InitCommand   = require('../../../lib/commands/init');
var td = require('testdouble');

describe('init command', function() {
  var ui, analytics, tasks, command;

  beforeEach(function() {
    ui = new MockUI();
    analytics = new MockAnalytics();
    tasks = {
      InstallBlueprint: Task.extend({}),
      NpmInstall: Task.extend({}),
      BowerInstall: Task.extend({})
    };
  });

  afterEach(function() {
    td.reset();
  });

  function buildCommand(projectOpts) {
    var options = {
      ui: ui,
      analytics: analytics,
      project: new Project(process.cwd(), projectOpts || { name: 'some-random-name' }),
      tasks: tasks,
      settings: {}
    };

    command = new InitCommand(options);
  }

  it('doesn\'t allow to create an application named `test`', function() {
    buildCommand({ name: 'test' });

    return command.validateAndRun([]).then(function() {
      expect(false, 'should have rejected with an application name of test').to.be.ok;
    })
    .catch(function(error) {
      expect(error.message).to.equal('We currently do not support a name of `test`.');
    });
  });

  it('doesn\'t allow to create an application without project name', function() {
    buildCommand({ name: undefined });

    return command.validateAndRun([]).then(function() {
      expect(false, 'should have rejected with an application without project name').to.be.ok;
    })
    .catch(function(error) {
      expect(error.message).to.equal('The `ember init` command requires a package.json in current folder with name attribute or a specified name via arguments. For more details, use `ember help`.');
    });
  });

  it('Uses the name of the closest project to when calling installBlueprint', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal('some-random-name');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun([])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses the provided app name over the closest found project', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal('provided-name');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['--name=provided-name'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses process.cwd if no package is found when calling installBlueprint', function() {
    // change the working dir so `process.cwd` can't be a invalid path for base directories
    // named `ember-cli`.

    var tmpDir = os.tmpdir();
    var workingDir = tmpDir + '/ember-cli-test-project';
    var currentWorkingDir = process.cwd();

    fs.mkdirSync(workingDir);
    process.chdir(workingDir);

    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal(path.basename(process.cwd()));
        return Promise.reject('Called run');
      }
    });

    buildCommand({ name: path.basename(process.cwd()) });

    return command.validateAndRun([])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      })
      .then(function() {
        process.chdir(currentWorkingDir);
        fs.rmdirSync(workingDir);
      });
  });

  it('doesn\'t use --dry-run or any other command option as the name', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal('some-random-name');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['--dry-run'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('doesn\'t use . as the name', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.rawName).to.equal('some-random-name');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['.'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses the "app" blueprint by default', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.blueprint).to.equal('app');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['--name=provided-name'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses arguments to select files to init', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.blueprint).to.equal('app');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['package.json', '--name=provided-name'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Uses the "addon" blueprint for addons', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts.blueprint).to.equal('addon');
        return Promise.reject('Called run');
      }
    });

    buildCommand({ keywords: ['ember-addon'], name: 'some-random-name' });

    return command.validateAndRun(['--name=provided-name'])
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });

  it('Registers blueprint options in beforeRun', function() {
    td.replace(Blueprint, 'lookup', td.function());
    td.when(Blueprint.lookup('app'), {ignoreExtraArgs: true}).thenReturn({
      availableOptions: [
        { name: 'custom-blueprint-option', type: String }
      ]
    });

    buildCommand();

    command.beforeRun(['app']);
    expect(map(command.availableOptions, 'name')).to.contain('custom-blueprint-option');
  });

  it('Passes command options through to the install blueprint task', function() {
    tasks.InstallBlueprint = Task.extend({
      run: function(blueprintOpts) {
        expect(blueprintOpts).to.contain.keys('customOption');
        expect(blueprintOpts.customOption).to.equal('customValue');
        return Promise.reject('Called run');
      }
    });

    buildCommand();

    return command.validateAndRun(['--custom-option=customValue'])
      .then(function() {
        expect(false, 'promise should have rejected').to.be.ok;
      })
      .catch(function(reason) {
        expect(reason).to.equal('Called run');
      });
  });
});
<|endoftext|>


<commit_before>/*!
 * superbly tagfield v0.1
 * http://www.superbly.ch
 *
 * Copyright 2011, Manuel Spierenburg
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://www.superbly.ch/licenses/mit-license.txt
 * http://www.superbly.ch/licenses/gpl-2.0.txt
 *
 * Date: Sun Apr 14 00:47:29 2011 -0500
 */
(function($){
    $.fn.superblyTagField = function(userOptions) {
        var settings = {
            allowNewTags:true,
            showTagsNumber:10,
            preset:[],
            tags:[],
        };

        if(userOptions) {
            $.extend(settings, userOptions);
        }

        superblyTagField(this, settings);

        return this;
    };

    var keyMap = {
        downArrow:40,
        upArrow:38,
        enter:13,
        space:32,
        tab:9,
        backspace:8
    }

    function superblyTagField(tagField, settings) {

        var tags = settings.tags.sort();
        var preset = settings.preset;
        var allowNewTags = settings.allowNewTags;
        var showTagsNumber = settings.showTagsNumber;

        var tagstmp = tags.slice();

        // prepare needed vars
        var inserted = new Array();
        var selectedIndex = null;
        var currentValue = null;
        var currentItem = null;
        var hoverSuggestItems = false;

        tagField.css('display', 'none');

        var superblyMarkup = '

<input class="superblyTagInput" type="text" autocomplete="false">

';
        tagField.after(superblyMarkup);

        var tagInput = $(".superblyTagInput", tagField.next());
        var suggestList = tagInput.next();
        var inputItem = tagInput.parent();
        var tagList = inputItem.parent();

        // set presets
        for(i in preset){
            addItem(preset[i]);
        }

        // events
        suggestList.mouseover(function(e){
            hoverSuggestItems = true;
        });

        suggestList.mouseleave(function(e){
            hoverSuggestItems = false;
        });

        tagInput.keyup(function(e){
            suggest($(this).val());
        });

        tagInput.focusout(function(e){
            if(!hoverSuggestItems){
                suggestList.css('display', 'none');
            }
            if(allowNewTags){
                var value = tagInput.val();
                if(value != null && value != ''){
                    addItem(value, false);
                }
            }
        });

        tagInput.focus(function(e){
            currentValue = null;
        });

        tagInput.keydown(function(e){
            if(e.keyCode == keyMap.downArrow) {
                selectDown();
            }else if(e.keyCode == keyMap.upArrow) {
                selectUp()
            }else if(e.keyCode == keyMap.enter || e.keyCode == keyMap.tab || e.keyCode == keyMap.space) {
                if(currentItem != null){
                    addItem(currentItem);
                } else if(allowNewTags){
                    var value = tagInput.val();
                    if(value != null && value != ''){
                        addItem(value);
                    }
                }
                // prevent default action for enter
                return e.keyCode != keyMap.enter;
            }else if(e.keyCode == keyMap.backspace){
                // backspace
                if(tagInput.val() == ''){
                    removeLastItem();
                }
                updateTagInputWidth();
            } else {
                updateTagInputWidth();
            }

        });

        tagList.parent().click(function(e){
            tagInput.focus();
        });

        // functions
        function setValue(){
            tagField.val(inserted.join(' '));
        }

        function updateTagInputWidth()
        {
            /*
            * To make tag wrapping behave as expected, dynamically adjust
            * the tag input's width to its content's width
            * The best way to get the content's width in pixels is to add it
            * to the DOM, grab the width, then remove it from the DOM.
            */
            var temp = $("").text(tagInput.val()).appendTo(inputItem);
            var width = temp.width();
            temp.remove();
            tagInput.width(width + 20);
        }

        function addItem(value, focus){
            var index = jQuery.inArray(value,tagstmp);
            if((jQuery.inArray(value,inserted) == -1) && ( index > -1 || allowNewTags)){
                //delete from tags
                if(index >-1){
                    tagstmp.splice(index,1);
                }
                inserted.push(value);
                inputItem.before("
" + value + " x
");
                tagInput.val("");
                currentValue = null;
                currentItem = null;
                // add remove click event
                var new_index = tagList.children('.superblyTagItem').size()-1;
                $(tagList.children('.superblyTagItem')[new_index]).children('a').click(function(e){
                    var value = $($(this).parent('.superblyTagItem').children('span')[0]).text();
                    removeItem(value);
                });
            }
            suggestList.css('display', 'none');
            updateTagInputWidth();
            setValue();
            if(focus === undefined || focus)
                tagInput.focus();
        }

        function removeItem(value){
            var index = jQuery.inArray(value,tags);
            var tmpIndex = jQuery.inArray(value,tagstmp);
            if(index > -1 && tmpIndex == -1){
                tagstmp.push(value);
            }
            index = jQuery.inArray(value,inserted);
            if(index > -1){
                inserted.splice(index,1);
                tagList.children(".superblyTagItem").filter(function(){return $('span', this).html() == value;}).remove();
            }
            tagstmp.sort();
            tagInput.focus();
            setValue();
        }

        function removeLastItem(){
            var last_index = inserted.length-1;
            var last_value = inserted[last_index];
            removeItem(last_value);
        }

        function getSuggestionsArray(value){
            var suggestions = new Array();
            var count = 0;
            for(key in tagstmp){
                if(showTagsNumber <= count){
                    break;
                }
                // if beginning is same
                var lower_case_tag = tagstmp[key].toLocaleLowerCase();
                var lower_cast_value = value.toLowerCase();
                if(lower_case_tag.indexOf(lower_cast_value) == 0){
                    suggestions.push(tagstmp[key]);
                    count++;
                }
            }
            return suggestions;
        }

        function suggest(value){
            load_suggestions(value);
        }

        /**
         * Perform an ajax request to the delapi /tags/suggest feauture
         *
         */
        function load_suggestions(value) {
            function request(options) {
                var defaults, opts;

                defaults = {
                    type: "GET",
                    dataType: "xml",
                    error: function(jqxhr, textStatus, errorThrown) {
                        console.log('failed to load suggestions');
                        console.log(textStatus);
                        console.log(jqxhr);
                        console.log(errorThrown);
                    }
                };

                opts = $.extend({}, defaults, options);
                $.ajax(opts);
            };

            var opts = {
                url: "http://127.0.0.1:6543/delapi/tags/complete",
                data: {tag: value},
                success: function (xml) {
                    tag_list = [];
                    results = $(xml).find("tag");
                    results.map(function () {
                        console.log($(this));
                        console.log($(this).text());
                        tag_list.push($(this).text());
                    });

                    tags = tag_list;
                    tagstmp = tags.slice();

                    // now onto what the suggest method wanted to do originally
                    suggestList.show();
                    if(value == currentValue){
                        return false;
                    }
                    currentValue = value;
                    suggestList.empty();
                    var suggestions = getSuggestionsArray(value);
                    for(key in suggestions){
                        suggestList.append("
" + suggestions[key] + "
");
                    }

                    var suggestionItems = suggestList.children('.superblySuggestItem');

                    // add click event to suggest items
                    suggestionItems.click(function(e){
                        addItem($(this).html());
                    });

                    selectedIndex=null;
                    if(!allowNewTags){
                        selectedIndex=0;
                        $(suggestionItems[selectedIndex]).addClass("selected");
                        currentItem = $(suggestionItems[selectedIndex]).html();
                    }

                }
            };

            request(opts);
        };

        function selectDown(){
            var suggestions = suggestList.children('.superblySuggestItem');
            var size = suggestions.size();
            if(selectedIndex == null){
                selectedIndex=0;
            }else if(selectedIndex < size-1){
                $(suggestions[selectedIndex]).removeClass("selected");
                selectedIndex++;
            }
            $(suggestions[selectedIndex]).addClass("selected");
            currentItem = $(suggestions[selectedIndex]).html();
        }

        function selectUp(){
            if(selectedIndex == 0){
                selectedIndex=null;
                currentItem = null;
                tagInput.focus();
            } else if(selectedIndex >0){
                var suggestions = suggestList.children('.superblySuggestItem');
                $(suggestions[selectedIndex]).removeClass("selected");
                selectedIndex--;
                $(suggestions[selectedIndex]).addClass("selected");
                currentItem = $(suggestions[selectedIndex]).html();
            }
        }
    }
})(jQuery);
<commit_msg>Progress on trying to get the ajax completion to work<commit_after>/*!
 * superbly tagfield v0.1
 * http://www.superbly.ch
 *
 * Copyright 2011, Manuel Spierenburg
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://www.superbly.ch/licenses/mit-license.txt
 * http://www.superbly.ch/licenses/gpl-2.0.txt
 *
 * Date: Sun Apr 14 00:47:29 2011 -0500
 */
(function($){
    $.fn.superblyTagField = function(userOptions) {
        var settings = {
            allowNewTags:true,
            showTagsNumber:10,
            preset:[],
            tags:[],
        };

        if(userOptions) {
            $.extend(settings, userOptions);
        }

        superblyTagField(this, settings);

        return this;
    };

    var keyMap = {
        downArrow:40,
        upArrow:38,
        enter:13,
        space:32,
        tab:9,
        backspace:8
    }

    function superblyTagField(tagField, settings) {

        var tags = settings.tags.sort();
        var preset = settings.preset;
        var allowNewTags = settings.allowNewTags;
        var showTagsNumber = settings.showTagsNumber;

        var tagstmp = tags.slice();

        // prepare needed vars
        var inserted = new Array();
        var selectedIndex = null;
        var currentValue = null;
        var currentItem = null;
        var hoverSuggestItems = false;

        tagField.css('display', 'none');

        var superblyMarkup = '

<input class="superblyTagInput" type="text" autocomplete="false">

';
        tagField.after(superblyMarkup);

        var tagInput = $(".superblyTagInput", tagField.next());
        var suggestList = tagInput.next();
        var inputItem = tagInput.parent();
        var tagList = inputItem.parent();

        // set presets
        for(i in preset){
            console.log('preset');

            addItem(preset[i]);
        }

        // events
        suggestList.mouseover(function(e){
            hoverSuggestItems = true;
        });

        suggestList.mouseleave(function(e){
            hoverSuggestItems = false;
        });

        tagInput.keyup(function(e){
            suggest($(this).val());
        });

        tagInput.focusout(function(e){
            if(!hoverSuggestItems){
                suggestList.css('display', 'none');
            }
            if(allowNewTags){
                var value = tagInput.val();
                if(value != null && value != ''){
                    console.log('focusout');
                    addItem(value, false);
                }
            }
        });

        tagInput.focus(function(e){
            currentValue = null;
        });

        tagInput.keydown(function(e){
            if(e.keyCode == keyMap.downArrow) {
                selectDown();
            }else if(e.keyCode == keyMap.upArrow) {
                selectUp()
            }else if(e.keyCode == keyMap.enter || e.keyCode == keyMap.tab || e.keyCode == keyMap.space) {
                if(currentItem != null){
                    console.log('in if');
                    addItem(currentItem);
                } else if(allowNewTags){
                    var value = tagInput.val();
                    if(value != null && value != ''){
                        console.log('in else');

                        addItem(value);
                    }
                }
                // prevent default action for enter
                return e.keyCode != keyMap.enter;
            }else if(e.keyCode == keyMap.backspace){
                // backspace
                if(tagInput.val() == ''){
                    removeLastItem();
                }
                updateTagInputWidth();
            } else {
                updateTagInputWidth();
            }

        });

        tagList.parent().click(function(e){
            tagInput.focus();
        });

        // functions
        function setValue(){
            tagField.val(inserted.join(' '));
        }

        function updateTagInputWidth()
        {
            /*
            * To make tag wrapping behave as expected, dynamically adjust
            * the tag input's width to its content's width
            * The best way to get the content's width in pixels is to add it
            * to the DOM, grab the width, then remove it from the DOM.
            */
            var temp = $("").text(tagInput.val()).appendTo(inputItem);
            var width = temp.width();
            temp.remove();
            tagInput.width(width + 20);
        }

        function addItem(value, focus){
            console.log('added value' + value);
            var index = jQuery.inArray(value,tagstmp);
            if((jQuery.inArray(value,inserted) == -1) && ( index > -1 || allowNewTags)){
                //delete from tags
                if(index >-1){
                    tagstmp.splice(index,1);
                }
                inserted.push(value);
                inputItem.before("
" + value + " x
");
                tagInput.val("");
                currentValue = null;
                currentItem = null;
                // add remove click event
                var new_index = tagList.children('.superblyTagItem').size()-1;
                $(tagList.children('.superblyTagItem')[new_index]).children('a').click(function(e){
                    var value = $($(this).parent('.superblyTagItem').children('span')[0]).text();
                    removeItem(value);
                });
            }
            suggestList.css('display', 'none');
            updateTagInputWidth();
            setValue();
            if(focus === undefined || focus)
                tagInput.focus();
        }

        function removeItem(value){
            var index = jQuery.inArray(value,tags);
            var tmpIndex = jQuery.inArray(value,tagstmp);
            if(index > -1 && tmpIndex == -1){
                tagstmp.push(value);
            }
            index = jQuery.inArray(value,inserted);
            if(index > -1){
                inserted.splice(index,1);
                tagList.children(".superblyTagItem").filter(function(){return $('span', this).html() == value;}).remove();
            }
            tagstmp.sort();
            tagInput.focus();
            setValue();
        }

        function removeLastItem(){
            var last_index = inserted.length-1;
            var last_value = inserted[last_index];
            removeItem(last_value);
        }

        function getSuggestionsArray(value){
            var suggestions = new Array();
            var count = 0;
            for(key in tagstmp){
                if(showTagsNumber <= count){
                    break;
                }
                // if beginning is same
                var lower_case_tag = tagstmp[key].toLocaleLowerCase();
                var lower_cast_value = value.toLowerCase();
                if(lower_case_tag.indexOf(lower_cast_value) == 0){
                    suggestions.push(tagstmp[key]);
                    count++;
                }
            }
            return suggestions;
        }

        function suggest(value){
            load_suggestions(value);
        }

        /**
         * Perform an ajax request to the delapi /tags/suggest feauture
         *
         */
        function load_suggestions(value) {
            function request(options) {
                var defaults, opts;

                defaults = {
                    type: "GET",
                    dataType: "xml",
                    error: function(jqxhr, textStatus, errorThrown) {
                        console.log('failed to load suggestions');
                        console.log(textStatus);
                        console.log(jqxhr);
                        console.log(errorThrown);
                    }
                };

                opts = $.extend({}, defaults, options);
                $.ajax(opts);
            };

            var opts = {
                url: "http://127.0.0.1:6543/delapi/tags/complete",
                data: {tag: value},
                success: function (xml) {
                    tag_list = [];
                    results = $(xml).find("tag");
                    results.map(function () {
                        console.log($(this));
                        console.log($(this).text());
                        tag_list.push($(this).text());
                    });

                    tags = tag_list;
                    tagstmp = tags.slice();

                    // now onto what the suggest method wanted to do originally
                    suggestList.show();
                    if (value == currentValue) {
                        return false;
                    }

                    currentValue = value;
                    suggestList.empty();

                    var suggestions = getSuggestionsArray(value);
                    for(key in suggestions){
                        suggestList.append("
" + suggestions[key] + "
");
                    }

                    var suggestionItems = suggestList.children('.superblySuggestItem');

                    console.log('binding suggestion items');

                    // add click event to suggest items
                    $('.superblySuggestItem').each(function () {
                        $(this).bind('click', function(e) {
                            console.log('clicked');
                            console.log($(this));
                            addItem($(this).html());
                            e.preventDefault();
                        });
                    });

                    console.log(suggestionItems);

                    selectedIndex=null;
                    if(!allowNewTags){
                        selectedIndex=0;
                        $(suggestionItems[selectedIndex]).addClass("selected");
                        currentItem = $(suggestionItems[selectedIndex]).html();
                    }

                }
            };

            request(opts);
        };

        function selectDown(){
            var suggestions = suggestList.children('.superblySuggestItem');
            var size = suggestions.size();
            if(selectedIndex == null){
                selectedIndex=0;
            }else if(selectedIndex < size-1){
                $(suggestions[selectedIndex]).removeClass("selected");
                selectedIndex++;
            }
            $(suggestions[selectedIndex]).addClass("selected");
            currentItem = $(suggestions[selectedIndex]).html();
        }

        function selectUp(){
            if(selectedIndex == 0){
                selectedIndex=null;
                currentItem = null;
                tagInput.focus();
            } else if(selectedIndex >0){
                var suggestions = suggestList.children('.superblySuggestItem');
                $(suggestions[selectedIndex]).removeClass("selected");
                selectedIndex--;
                $(suggestions[selectedIndex]).addClass("selected");
                currentItem = $(suggestions[selectedIndex]).html();
            }
        }
    }
})(jQuery);
<|endoftext|>


<commit_before>// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name SelecTable.js
// ==/ClosureCompiler==

/**
 * @license The MIT License (MIT)
 *
 * Copyright (c) 2014 c0ff3m4r <l34k@bk.ru>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

function clear_selection(){
    if (window.getSelection) {
      if (window.getSelection().empty) {  // Chrome
        window.getSelection().empty();
      } else if (window.getSelection().removeAllRanges) {  // Firefox
        window.getSelection().removeAllRanges();
      }
    } else if (document.selection) {  // IE?
      document.selection.empty();
    }
}

/**
 * @constructor
 * @param {Element|string} table The table element or its Id.
 * @param {Object} options       Options
 * @export
 */
var SelecTable = function(table, options)
{
    var checkbox, row_i, cb_i;

    /** @dict */
    this.defaults = {
        'cssSelected': 'selected',
        'cssFocused': 'focused',
        'focusCheckbox': true,
        'allCheckbox': false
    }

    // parse options to this.config
    /** @type {!Object} */
    this.config = {}
    for (variable in this.defaults)
    {
        if (options && options.hasOwnProperty(variable))
            this.config[variable] = options[variable];
        else
            this.config[variable] = this.defaults[variable];
    }

    if(this.config.cssFocused)
        this.reFocused = new RegExp("(?:^|\\s)"+ this.config.cssFocused +"(?!\\S)","g");
    if(this.config.cssSelected)
        this.reSelected = new RegExp("(?:^|\\s)"+ this.config.cssSelected +"(?!\\S)","g");

    if (typeof table == "string")
        this.table = document.getElementById(table);
    else
        this.table = table;

    // assuming we have only one body
    this.rows = this.table.tBodies[0].rows;

    /** @type {?number} */
    this.selected = null;
    /** @type {number} */
    this.selectedCount = 0;
    // configure checkboxes

    if(this.config.allCheckbox)
    {
        if (typeof this.config.allCheckbox == "string")
            this.config.allCheckbox = document.getElementById(this.config.allCheckbox);

        this.config.allCheckbox.onchange = this.getAllCheckboxOnchange();
    }

    for(row_i=0; row_i<this.rows.length; row_i++)
    {
        checkbox = this.rows[row_i].getElementsByTagName('input');
        for(cb_i=0; cb_i < checkbox.length && checkbox[cb_i].type != "checkbox"; cb_i++){}
        checkbox = checkbox[cb_i];
        this.rows[row_i].setAttribute('unselectable', 'on'); // IE fix
        checkbox.onclick = this.getCheckboxOnclick();
        if(checkbox.checked)
            this.select(row_i, true);
        this.rows[row_i].onclick = this.getRowOnclick()
        this.rows[row_i].checkbox = checkbox;
        this.rows[row_i].checkbox.row = this.rows[row_i];
    }
}

/**
 * Select a row.
 * @param {!Element|number} index The row number or object to select.
 * @param {boolean=} changefocus Change the focus to this element?.
 * @export
 */
SelecTable.prototype.select = function(index, changefocus){
    if(typeof(changefocus) === 'undefined') changefocus = true;
    index = this.getRowIndex(index);
    if (changefocus){
        if(this.config.cssFocused)
        {
            if (this.selected != null)
            {
                this.selected.className = this.selected.className.replace(this.reFocused, "");
            }
            this.rows[index].className += ' ' + this.config.cssFocused;
        }
        this.selected = this.rows[index];
        if (this.config.focusCheckbox)
            this.rows[index].checkbox.focus();
    }
    if (this.config.cssSelected)
        this.rows[index].className += ' ' + this.config.cssSelected;
    if(!this.rows[index].checkbox.checked)
        // increment counter only if it wasn't checked
        this.selectedCount += 1;
    this.rows[index].checkbox.checked = true;
};

/**
 * @param {!Element|number} index The row number or object to unselect.
 * @export
 */
SelecTable.prototype.unselect = function(index)
{
    index = this.getRowIndex(index);
    if (this.config.cssSelected)
    {
        this.rows[index].className = this.rows[index].className.replace(this.reSelected, "");
    }
    if(this.rows[index].checkbox.checked)
        // decrement counter only if it was checked
        this.selectedCount -= 1;
    this.rows[index].checkbox.checked = false;
};

/**
 * @param {!Element|number} index The row number or object to toggle.
 * @export
 */
SelecTable.prototype.toggle = function(index)
{
    index = this.getRowIndex(index);
    if(this.rows[index].checkbox.checked) this.unselect(index);
    else this.select(index, true);
};

/**
 * @param {!Element|number} row The row number or object to unselect.
 */
SelecTable.prototype.getRowIndex = function(row){
    if (typeof o === 'number') return row;
    if (typeof row.rowIndex == "undefined") return row;
    return row.rowIndex - this.table.tHead.rows.length;
}

/**
 * @param {!Element|number} row The row number or object to unselect.
 * @export
 */
 SelecTable.prototype.getRowIsSelected = function(row)
{
    return this.rows[this.getRowIndex(row)].checkbox.checked;
}

/**
 * Select all
 */
SelecTable.prototype.selectAll = function()
{
    for(var i=this.rows.length - 1; i >= 0; i--)
        this.select(i, true);
};

/**
 * Get Onchange Function for the checkbox which controlls
 * all rows.
 */
SelecTable.prototype.getAllCheckboxOnchange = function()
{
    var table = this
    return function()
{
        if(this.checked)
        {
            table.selectAll()
        }else{
            table.unselectAll()
        }
    }
}
/**
 *
 * @param {!Element|number} index
 */
SelecTable.prototype.selectOnly = function(index)
{
    index = this.getRowIndex(index);
    this.unselectAll();
    this.select(index);
}
/**
 *
 * @param {!Element|number} start
 * @param {!Element|number} stop
 */
SelecTable.prototype.selectRange = function(start, stop)
{
    var i, a=1;
    start = this.getRowIndex(start);
    stop = this.getRowIndex(stop);
    if(start > stop) a = -1;
    for (i = start; i != stop; i += a) {
        this.select(i, false);
    };
    this.select(stop, true);
}

SelecTable.prototype.unselectAll = function()
{
    for (var i=0; i<this.rows.length; i++)
        this.unselect(i);
}

SelecTable.prototype.getRowOnclick = function()
{
    var table = this;
    return function(e){
        //e.stopPropagation();
        // select functionallity
        if (event.ctrlKey == 1) {
            table.toggle(this);
        }else if (event.shiftKey == 1){
            if (table.selected != null)
                table.selectRange(table.selected, this);
        }else{
            // select it if it wasn't selected already
            // or if the object wasn't the only one
            if(!table.getRowIsSelected(this) || table.selectedCount > 1)
                table.selectOnly(this);
            else
                table.unselectAll();
        }
        if (event.shiftKey == 1)
            // if there was something selected
            // we clear it.
            clear_selection();
    }
}

SelecTable.prototype.getCheckboxOnclick = function()
{
    var table = this;
    return function(e)
    {

        e.stopPropagation();
        var index = this.row;
        if(this.checked)
            table.select(index, true);
        else
            table.unselect(index);
    }
}

window['SelecTable'] = SelecTable;
<commit_msg>Some improvements for closure compiler<commit_after>// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name SelecTable.js
// ==/ClosureCompiler==

/**
 * @license The MIT License (MIT)
 * Copyright (c) 2014 c0ff3m4r <l34k@bk.ru>
 */
/* Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * @constructor
 * @param {HTMLElement|string} table The table element or its Id.
 * @param {Object} options       Options
 * @export
 */
var SelecTable = function(table, options)
{
    /** @type{HTMLElement} */
    var checkbox
    /** @type{!NodeList} */
    var inputs
    /** @type{number} */
    var row_i;
    /** @type{number} */
    var cb_i;

    /** @type{!Object} */
    var sTable = this;

    /** @dict */
    this.defaults = {
        'cssSelected': 'selected',
        'cssFocused': 'focused',
        'focusCheckbox': true,
        'allCheckbox': false
    }

    // parse options to this.config
    /** @dict */
    this.config = {}
    for (variable in this.defaults)
    {
        if (options && options.hasOwnProperty(variable))
            this.config[variable] = options[variable];
        else
            this.config[variable] = this.defaults[variable];
    }

    function clear_selection(){
        if (window.getSelection) {
          if (window.getSelection().empty) {  // Chrome
            window.getSelection().empty();
          } else if (window.getSelection().removeAllRanges) {  // Firefox
            window.getSelection().removeAllRanges();
          }
        } else if (document.selection) {  // IE?
          document.selection.empty();
        }
    }

    /** @this{!HTMLElement} */
    function checkboxOnclick(e)
    {
            // prevent row from beiing clicked
            e.stopPropagation();
            var index = this['row'];
            if(this.checked)
                sTable.select(index, true);
            else
                sTable.unselect(index);
    }

    /**
     * @type{RegExp|null}
     * @private
     */
    this.reFocused = null;

    /**
     * @type{RegExp|null}
     * @private
     */
    this.reSelected = null;

    if(this.config['cssFocused'])
    {
        this.reFocused = new RegExp("(?:^|\\s)"+ this.config['cssFocused'] +"(?!\\S)","g");
    }

    if(this.config['cssSelected'])
        this.reSelected = new RegExp("(?:^|\\s)"+ this.config['cssSelected'] +"(?!\\S)","g");

    if (typeof table == "string")
    {
        table = document.getElementById(table);
        if(table === null) return;
    }
    /** @type {HTMLElement} */
    this.table = table;

    /** @type {Array.<HTMLElement>} */
    var rows = table.tBodies[0].rows;

    /** @type {?HTMLElement}
     *  @private
     */
    this.selected = null;

    /**
     * @type {number}
     * @private
     */
    this.selectedCount = 0;

    /** @type {HTMLElement} */
    var all_checkbox = this.config['allCheckbox'];
    // configure checkboxes
    if(all_checkbox)
    {
        if (typeof all_checkbox == "string")
            all_checkbox = document.getElementById(this.config['allCheckbox']);

        all_checkbox.onchange = function()
        {
            if(this.checked)
            {
                sTable.selectAll()
            }else{
                sTable.unselectAll()
            }
        };
    }

    for(row_i=0; row_i<rows.length; row_i++)
    {
        inputs = rows[row_i].getElementsByTagName('input');
        rows[row_i]['checkbox'] = null;
        for(cb_i=0; cb_i < inputs.length; cb_i++){
            if(inputs[cb_i].type == "checkbox"){

                inputs[cb_i].onclick = checkboxOnclick;

                if(inputs[cb_i].checked)
                {
                    this.select(row_i, true);
                }
                inputs[cb_i]['row'] = rows[row_i]
                rows[row_i]['checkbox'] = inputs[cb_i];
                break;
            }
        }
        rows[row_i].setAttribute('unselectable', 'on'); // IE fix

        /**
         * The onclick function for rows
         */
        rows[row_i].onclick = function(e)
        {
            var row;
            if(!e) e = event;
            if (e.ctrlKey == 1) {
                sTable.toggle(this);
            }else if (e.shiftKey == 1){
                row = sTable.getSelectedRow();
                if (row !== null)  sTable.selectRange(row, this);
            }else{
                // select it if it wasn't selected already
                // or if the object wasn't the only one
                if(!sTable.getRowIsSelected(this) || sTable.selectedCount > 1)
                    sTable.selectOnly(this);
                else
                    sTable.unselectAll();
            }
            if (e.shiftKey == 1)
            {
                // if there was something selected
                // we clear it.
                clear_selection();
            }
        }

    }
    /** @type {Array.<HTMLElement>} */
    this.rows = rows;
}

/**
 * Select a row.
 *
 * @param {!HTMLElement|number} index The row number or object to select.
 * @param {boolean=} changefocus Change the focus to this element?.
 */
SelecTable.prototype.select = function(index, changefocus){
    if(typeof(changefocus) === 'undefined') changefocus = true;
    index = this._getRowIndex(index);
    /** @type{HTMLElement} */
    var row = this.rows[index];
    /** @type{HTMLElement} */
    var checkbox = row['checkbox'];

    if (changefocus){
        if(this.reFocused)
        {
            if (this.selected != null)
            {
                this.selected.className = this.selected.className.replace(this.reFocused, "");
            }
            row.className += ' ' + this.config['cssFocused'];
        }
        this.selected = this.rows[index];
        if (this.config['focusCheckbox'] && checkbox)
        {
            checkbox.focus();
        }
    }
    if (this.reSelected) row.className += ' ' + this.config['cssSelected'];
    if(checkbox)
    {
        if(!checkbox.checked)
            // increment counter only if it wasn't checked
            this.selectedCount ++;
        checkbox.checked = true;
    }
};

/**
 * @param {!HTMLElement|number} index The row number or object to unselect.
 */
SelecTable.prototype.unselect = function(index)
{
    index = this._getRowIndex(index);
    /** @type{HTMLElement} */
    var row = this.rows[index];
    /** @type{HTMLElement} */
    var checkbox = row['checkbox'];
    if (this.reSelected)
    {
        row.className = row.className.replace(this.reSelected, "");
    }
    if(checkbox)
    {
        if(checkbox.checked)
            // decrement counter only if it was checked
            this.selectedCount --;
        checkbox.checked = false;
    }
};

/**
 * @param {!HTMLElement|number} index The row number or object to toggle.
 */
SelecTable.prototype.toggle = function(index)
{
    index = this._getRowIndex(index);
    if(this.rows[index]['checkbox'].checked) this.unselect(index);
    else this.select(index, true);
};

/**
 * @param {!HTMLElement|number} row The row number or object to unselect.
 * @private
 */
SelecTable.prototype._getRowIndex = function(row){
    if (typeof row === 'number') return row;
    if(!row || typeof row.nodeType !== 'number' && row.nodeType == 3) throw row;
    return row.rowIndex - this.table.tHead.rows.length;
}

/**
 * @param {!HTMLElement|number} row
 * @return {boolean}
 */
 SelecTable.prototype.getRowIsSelected = function(row)
{
    return this.rows[this._getRowIndex(row)]['checkbox'].checked;
}

/**
 * Returns the currently selected row.
 * @return{?HTMLElement}
 */
SelecTable.prototype.getSelectedRow = function()
{
    return this.selected;
}

/**
 * Select all
 */
SelecTable.prototype.selectAll = function()
{
    for(var i=this.rows.length - 1; i >= 0; i--)
        this.select(i, true);
};

/**
 * @param {!HTMLElement|number} index
 */
SelecTable.prototype.selectOnly = function(index)
{
    index = this._getRowIndex(index);
    this.unselectAll();
    this.select(index);
}
/**
 * @param {!HTMLElement|number} start
 * @param {!HTMLElement|number} stop
 * @private
 */
SelecTable.prototype.selectRange = function(start, stop)
{
    var i, a=1;
    /** @type{number} */
    var start_index = this._getRowIndex(start);
    /** @type{number} */
    var stop_index = this._getRowIndex(stop);
    if(start_index > stop_index) a = -1;
    for (i = start_index; i != stop_index; i += a) {
        this.select(i, false);
    };
    this.select(stop, true);
}

SelecTable.prototype.unselectAll = function()
{
    for (var i=0; i<this.rows.length; i++)
        this.unselect(i);
}

// Export
window['SelecTable'] = SelecTable;
Select.prototype['getSelectedRow'] = SelecTable.prototype.getSelectedRow;
// SelecTable.prototype['select'] = SelecTable.prototype.select;
// SelecTable.prototype['unselect'] = SelecTable.prototype.unselect;
// SelecTable.prototype['toggle'] = SelecTable.prototype.toggle;<|endoftext|>


<commit_before>/**
 * @file Accordion component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef, cloneElement} from 'react';
import PropTypes from 'prop-types';

// Components
import RaisedButton from '../RaisedButton';

// Statics
import Theme from '../Theme';

// Vendors
import classNames from 'classnames';
import ComponentUtil from '../_vendors/ComponentUtil';

class Accordion extends Component {

    static Theme = Theme;

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            collapsed: ComponentUtil.getDerivedState(props, state, 'collapsed')
        };
    }

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.accordionContent = createRef();

        this.state = {
            collapsed: props.collapsed,
            contentHeight: null
        };

    }

    componentDidMount() {
        this.init();
    }

    /**
     * public
     */
    resetHeight = callback => {

        const el = this.accordionContent?.current;
        if (this.state.collapsed || !el) {
            return;
        }

        const style = window.getComputedStyle(el);
        if (!style) {
            return;
        }

        this.setState({
            contentHeight: 'auto'
        }, () => {
            this.setState({
                contentHeight: el.clientHeight
            }, () => {
                callback?.();
                this.props.onResetHeight?.(el.clientHeight);
            });
        });

    };

    /**
     * public
     */
    collpase = () => {
        this.setState({
            collapsed: true
        }, () => {
            this.props.onCollpase?.();
            this.props.onChange?.(true);
        });
    };

    /**
     * public
     */
    expand = () => {
        this.setState({
            collapsed: false
        }, () => {
            this.props.onExpand?.();
            this.props.onChange?.(false);
        });
    };

    handleClick = () => {
        this.state.collapsed ?
            this.expand()
            :
            this.collpase();
    };

    init = () => {
        if (!this.props.collapsed) {
            this.resetHeight();
        } else {
            setTimeout(() => {
                this.setState({
                    collapsed: false
                }, () => {
                    this.resetHeight(() => {
                        this.setState({
                            collapsed: this.props.collapsed
                        });
                    });
                });
            }, 0);
        }
    };

    render() {

        const {children, className, style, title, collapseIcon, titleRenderer} = this.props,
            {collapsed, contentHeight} = this.state;

        return (

                {
                    titleRenderer ?
                        typeof titleRenderer === 'function' ?
                            titleRenderer(this.handleClick)
                            :
                            cloneElement(titleRenderer, {
                                onClick: this.handleClick
                            })
                        :
                        <RaisedButton className="accordion-title"
                                      theme={Theme.SECONDARY}
                                      value={title}
                                      rightIconCls={collapseIcon}
                                      onClick={this.handleClick}/>
                }

                    {children}

        );

    }
}

Accordion.propTypes = {

    children: PropTypes.any,

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The accordion's title.
     */
    title: PropTypes.any,

    collapsed: PropTypes.bool,

    titleRenderer: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),

    /**
     * Collapse icon.
     */
    collapseIcon: PropTypes.string,

    /**
     * Callback function fired when collpase the accordion.
     */
    onCollpase: PropTypes.func,

    /**
     * Callback function fired when expand the accordion.
     */
    onExpand: PropTypes.func,

    /**
     * Callback function fired when change the status of accordion.
     */
    onChange: PropTypes.func,

    onResetHeight: PropTypes.func

};

Accordion.defaultProps = {
    title: 'title',
    collapsed: false,
    collapseIcon: 'fas fa-angle-down'
};

export default Accordion;
<commit_msg>update Accordion<commit_after>/**
 * @file Accordion component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef, cloneElement} from 'react';
import PropTypes from 'prop-types';

// Components
import RaisedButton from '../RaisedButton';

// Statics
import Theme from '../Theme';

// Vendors
import classNames from 'classnames';
import ComponentUtil from '../_vendors/ComponentUtil';

class Accordion extends Component {

    static Theme = Theme;

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            collapsed: ComponentUtil.getDerivedState(props, state, 'collapsed')
        };
    }

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.accordionContent = createRef();

        this.state = {
            collapsed: props.collapsed,
            contentHeight: null
        };

    }

    componentDidMount() {
        this.init();
    }

    /**
     * public
     */
    resetHeight = callback => {

        const el = this.accordionContent?.current;
        if (this.state.collapsed || !el) {
            return;
        }

        this.setState({
            contentHeight: 'auto'
        }, () => {
            this.setState({
                contentHeight: el.clientHeight
            }, () => {
                callback?.();
                this.props.onResetHeight?.(el.clientHeight);
            });
        });

    };

    /**
     * public
     */
    collpase = () => {
        this.setState({
            collapsed: true
        }, () => {
            this.props.onCollpase?.();
            this.props.onChange?.(true);
        });
    };

    /**
     * public
     */
    expand = () => {
        this.setState({
            collapsed: false
        }, () => {
            this.props.onExpand?.();
            this.props.onChange?.(false);
        });
    };

    handleClick = () => {
        this.state.collapsed ?
            this.expand()
            :
            this.collpase();
    };

    init = () => {
        if (!this.props.collapsed) {
            this.resetHeight();
        } else {
            setTimeout(() => {
                this.setState({
                    collapsed: false
                }, () => {
                    this.resetHeight(() => {
                        this.setState({
                            collapsed: this.props.collapsed
                        });
                    });
                });
            }, 0);
        }
    };

    render() {

        const {children, className, style, title, collapseIcon, titleRenderer} = this.props,
            {collapsed, contentHeight} = this.state;

        return (

                {
                    titleRenderer ?
                        typeof titleRenderer === 'function' ?
                            titleRenderer(this.handleClick)
                            :
                            cloneElement(titleRenderer, {
                                onClick: this.handleClick
                            })
                        :
                        <RaisedButton className="accordion-title"
                                      theme={Theme.SECONDARY}
                                      value={title}
                                      rightIconCls={collapseIcon}
                                      onClick={this.handleClick}/>
                }

                    {children}

        );

    }
}

Accordion.propTypes = {

    children: PropTypes.any,

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The accordion's title.
     */
    title: PropTypes.any,

    collapsed: PropTypes.bool,

    titleRenderer: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),

    /**
     * Collapse icon.
     */
    collapseIcon: PropTypes.string,

    /**
     * Callback function fired when collpase the accordion.
     */
    onCollpase: PropTypes.func,

    /**
     * Callback function fired when expand the accordion.
     */
    onExpand: PropTypes.func,

    /**
     * Callback function fired when change the status of accordion.
     */
    onChange: PropTypes.func,

    onResetHeight: PropTypes.func

};

Accordion.defaultProps = {
    title: 'title',
    collapsed: false,
    collapseIcon: 'fas fa-angle-down'
};

export default Accordion;
<|endoftext|>


<commit_before>/**
 * @file Accordion component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import RaisedButton from '../RaisedButton';
import Theme from '../Theme';
import ComponentUtil from '../_vendors/ComponentUtil';

class Accordion extends Component {

    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            collapsed: props.collapsed,
            contentHeight: null
        };

    }

    /**
     * public
     */
    resetHeight = () => {

        if (this.state.collapsed) {
            return;
        }

        const el = this.refs.accordionContent;

        if (!el) {
            return;
        }

        const style = window.getComputedStyle(el);

        if (!style) {
            return;
        }

        this.setState({
            contentHeight: 'auto'
        }, () => {
            this.setState({
                contentHeight: el.clientHeight
            });
        });

    };

    clickHandler = () => {

        const {onCollpase, onExpand, onChange} = this.props;

        const collapsed = !this.state.collapsed;

        this.setState({
            collapsed
        }, () => {
            if (collapsed) {
                onCollpase && onCollpase();
                onChange && onChange(true);
            } else {
                onExpand && onExpand();
                onChange && onChange(false);
            }
        });

    };

    componentDidMount() {
        this.resetHeight();
    }

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            collapsed: ComponentUtil.getDerivedState(props, state, 'collapsed')
        };
    }

    render() {

        const {className, style, children, title, collapseIcon} = this.props,
            {collapsed, contentHeight} = this.state,

            wrapperClassName = classNames('accordion', {
                collapsed: collapsed,
                [className]: className
            });

        return (

                <RaisedButton className="accordion-title"
                              theme={Theme.SECONDARY}
                              value={title}
                              rightIconCls={collapseIcon}
                              onClick={this.clickHandler}/>

                    {children}

        );

    }
}

Accordion.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The accordion's title.
     */
    title: PropTypes.string,

    collapsed: PropTypes.bool,

    /**
     * Collapse icon.
     */
    collapseIcon: PropTypes.string,

    /**
     * Callback function fired when collpase the accordion.
     */
    onCollpase: PropTypes.func,

    /**
     * Callback function fired when expand the accordion.
     */
    onExpand: PropTypes.func,

    /**
     * Callback function fired when change the status of accordion.
     */
    onChange: PropTypes.func

};

Accordion.defaultProps = {
    title: 'title',
    collapsed: false,
    collapseIcon: 'fas fa-angle-down'
};

export default Accordion;
<commit_msg>update Accordion<commit_after>/**
 * @file Accordion component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import RaisedButton from '../RaisedButton';
import Theme from '../Theme';
import ComponentUtil from '../_vendors/ComponentUtil';

class Accordion extends Component {

    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            collapsed: props.collapsed,
            contentHeight: null
        };

    }

    /**
     * public
     */
    resetHeight = () => {

        if (this.state.collapsed) {
            return;
        }

        const el = this.refs.accordionContent;

        if (!el) {
            return;
        }

        const style = window.getComputedStyle(el);

        if (!style) {
            return;
        }

        this.setState({
            contentHeight: 'auto'
        }, () => {
            this.setState({
                contentHeight: el.clientHeight
            });
        });

    };

    /**
     * public
     */
    collpase = () => {
        this.setState({
            collapsed: true
        }, () => {
            const {onCollpase, onChange} = this.props;
            onCollpase && onCollpase();
            onChange && onChange(true);
        });
    };

    /**
     * public
     */
    expand = () => {
        this.setState({
            collapsed: false
        }, () => {
            const {onExpand, onChange} = this.props;
            onExpand && onExpand();
            onChange && onChange(false);
        });
    };

    clickHandler = () => {
        this.state.collapsed ?
            this.expand()
            :
            this.collpase();
    };

    componentDidMount() {
        this.resetHeight();
    }

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            collapsed: ComponentUtil.getDerivedState(props, state, 'collapsed')
        };
    }

    render() {

        const {className, style, children, title, collapseIcon} = this.props,
            {collapsed, contentHeight} = this.state,

            wrapperClassName = classNames('accordion', {
                collapsed: collapsed,
                [className]: className
            });

        return (

                <RaisedButton className="accordion-title"
                              theme={Theme.SECONDARY}
                              value={title}
                              rightIconCls={collapseIcon}
                              onClick={this.clickHandler}/>

                    {children}

        );

    }
}

Accordion.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The accordion's title.
     */
    title: PropTypes.string,

    collapsed: PropTypes.bool,

    /**
     * Collapse icon.
     */
    collapseIcon: PropTypes.string,

    /**
     * Callback function fired when collpase the accordion.
     */
    onCollpase: PropTypes.func,

    /**
     * Callback function fired when expand the accordion.
     */
    onExpand: PropTypes.func,

    /**
     * Callback function fired when change the status of accordion.
     */
    onChange: PropTypes.func

};

Accordion.defaultProps = {
    title: 'title',
    collapsed: false,
    collapseIcon: 'fas fa-angle-down'
};

export default Accordion;
<|endoftext|>


<commit_before>"use strict";

var assert = require('assert');

var smush = function(a,b) {
  var c = smush2(a,b);
  var d = smush2(b,a);

  return c.length > d.length ? d : c;
};

var smush2 = function(a,b) {
  if (b.indexOf(a) === 0) {
    return b;
  } else {
    return a[0] + smush2(a.substr(1), b);
  }
};

var smushWords = function(words) {

};

describe('word smushing', function() {
  describe('base cases', function() {
    it('should find the minimal smush', function() {
      var smushed = smush('it', 'to');
      assert.equal('ito', smushed);
    });
  });

  describe('smush2', function() {
    it('should smush2 in the order specified', function() {
      var smushed = smush2('to', 'it');
      assert.equal('toit', smushed);
    });

    it('aligns smushes', function() {
      var smushed = smush2('it','to');
      assert.equal('ito', smushed);
    });
  });

  describe('small values', function() {
    var words = ['testing', 'ginger', 'german', 'minutes'];

    it('should find a minimal solution', function() {
      var smushed = smushWords(words);

      assert.equal('minutestingingerman', smushed);
    });
  });
});
<commit_msg>i\'m writing too much code with this commit, so note it down<commit_after>"use strict";

var assert = require('assert');

var smush = function(a,b) {
  var c = smush2(a,b);
  var d = smush2(b,a);

  return c.length > d.length ? d : c;
};

var smush2 = function(a,b) {
  if (b.indexOf(a) === 0) {
    return b;
  } else {
    return a[0] + smush2(a.substr(1), b);
  }
};

var smushWords = function(words) {
  // Will a greedy match work?
  var n = words.length;
  if (n === 2) {
    return smush(words[0], words[1]);
  } else {
    throw Error('writing too much code');
  }
};

describe('word smushing', function() {
  describe('base cases', function() {
    it('should find the minimal smush', function() {
      var smushed = smush('it', 'to');
      assert.equal('ito', smushed);
    });
  });

  describe('smush2', function() {
    it('should smush2 in the order specified', function() {
      var smushed = smush2('to', 'it');
      assert.equal('toit', smushed);
    });

    it('aligns smushes', function() {
      var smushed = smush2('it','to');
      assert.equal('ito', smushed);
    });
  });

  describe('small values', function() {
    var words = ['testing', 'ginger', 'german', 'minutes'];

    it('should find a minimal solution', function() {
      var smushed = smushWords(words);

      assert.equal('minutestingingerman', smushed);
    });
  });
});
<|endoftext|>