LogicNode = Object.subClass({

	init: function(config) {
		this.level = config.level || 0;
		this.type = config.type;
		this.expression = config.expression;
		this.condition = config.condition;
		this.valuation = config.valuation;
		this.parent = config.parent;
		this.children = [];
	},

	toString: function(content) {
		var result = "";

		if (!this.condition) {
			this.expression = this.valuation.expression = this.valuation.editor.val();
		}
		else {
			this.condition.expression = this.condition.editor.val();
			this.valuation.expression = this.valuation.editor.val();

			this.expression = this.condition.expression + "?" + this.valuation.expression;
		}

		result = result + this.expression;
		var flag = this.level == 0 ? ";" : ",";

		var max = this.children.length;
		for (var i = 0; i < max; i++) {
			var child = this.children[i];
			result = result + flag + child.toString();
		}
	},

	show: function() {
		if (!this.condition) {
			this.valuation.editor.val(this.valuation.expression);
		}
		else {
			this.condition.editor.val(this.condition.expression);
			this.valuation.editor.val(this.valuation.expression);
		}
	},

	clear: function() {
		if (this.condition && this.condition.el) {
			this.condition.el.remove();
		}
		if (this.valuation && this.valuation.el) {
			this.valuation.el.remove();
		}
		if (this.el) {
			this.el.remove();
		}
	}
});

LogicTree = Object.subClass({

	init: function(config) {
		this.type;
		this.condition = null;
		this.valuation = null;
		this.eidtor = null;
		this.children = [];
	},

	parse: function(content, flag) {
		this.clear();

		//1. if empty add default line
		if (!content) {
			this.parseMathValue(this, content, 0);
			return;
		}

		flag = flag || ";";

		//2. math
		if (content.indexOf(";") < 0) {
			this.parseMathValue(this, content, 0);
			return;
		}

		//3. logic
		var sequences = content.split(";");
		var max = sequences.length;

		for (var i = 0; i < max; i++) {
			sequence = sequences[i];
			var node = this.parseIFValue(this, sequence, 0);
		}
	},

	parseMathValue: function(parent, value, level) {
		var node = new LogicNode({
			parent: parent,
			level: level,
			type: "Math",
			valuation: {
				expression: value,
				el: null
			}
		});

		parent.children.push(node);
		return node;
	},

	parseIFValue: function(parent, content, level) {
		var pos = content.indexOf("?");

		//1. else if
		if (pos < 0) {
			var node = new LogicNode({
				parent: parent,
				level: level,
				type: "ELSE",
				expression: content,
				valuation: {
					expression: content,
					el: null
				}
			});

			parent.children.push(node);
			return;
		}

		//2. if condition
		var node = new LogicNode({
			parent: parent,
			level: level,
			type: "IF",
			condition: {
				expression: content.substring(0, pos),
				el: null
			}
		});
		node.expression = content;
		parent.children.push(node);

		//3. if valuation
		var pos_subflag = content.indexOf(",");
		if (pos_subflag < 0) {
			var math = content.substring(pos + 1);

			node.valuation = {
				expression: math,
				el: null
			}
			return;
		}

		//4. children
		this.parse(node, ",", 1);
	},

	gotoEmptyMathLogic: function() {
		if ("Math" == this.type) {
			return;
		}

		this.clear();
		this.parseMathValue(this, null, 0);
	},

	gotoEmptyIFLogic: function() {
		if ("IF" == this.type) {
			return;
		}

		this.clear();

		//1. if
		var node = new LogicNode({
			parent: this,
			level: 0,
			type: "IF",
			expression: null,
			condition: {
				expression: null,
				el: null
			},
			valuation: {
				expression: null,
				el: null
			}
		});
		this.children.push(node);

		//2. else
		node = new LogicNode({
			parent: this,
			level: 0,
			type: "ELSE",
			expression: null,
			valuation: {
				expression: null,
				el: null
			}
		});
		this.children.push(node);
	},

	getString: function() {
		var result = "";

		var max = this.children.length;
		for (var i = 0; i < max; i++) {
			var child = this.children[i];
			result = result + child.toString();
		}

		return result;
	},

	show: function() {
		var max = this.children.length;
		for (var i = 0; i < max; i++) {
			var child = this.children[i];
			child.show();
		}
	},

	clear: function() {
		var max = this.children.length;
		for (var i = 0; i < max; i++) {
			var child = this.children[i];
			child.clear();
		}

		this.children = [];
	}
});

FormulaDesigner = Control.subClass({

	items: true,

	init: function(config) {
		config.css = util.combine(config.css, {
			container: null
		});

		this.columnSetting = this.createSetting();

		this.logicTree = new LogicTree({});
		this.mathLine = {};
		this.selected = null;
		this.Code = {
			BackSpace: 8,
			Delete: 46,
			Enter: 13,
			TrigerBegin: 219,
			TrigerEnd: 221
		};
		this.tipList = {

		};

		Control.call(this, config);
	},

	getContainerTemplate: function() {
		return $(Formula_Template.container.join(""));
	},

	createContent: function() {
		this.logicTree.el = this.container;

		//1. body
		this.logicTree.el.body = $("#formula_body", this.container);

		//2. header
		this.header = $("#formula_header", this.container);
		var me = this;

		//2.1 header - name
		var codeEditor = this.header.codeEditor = $("#editor_code", this.header);
		codeEditor.change(function() { me.onChangeVariantCode.call(me) });

		var nameEditor = this.header.nameEditor = $("#editor_name", this.header);
		nameEditor.change(function() { me.onChangeVariantName.call(me) });

		nameEditor.focus(function () {
			nameEditor.preValue = nameEditor.val();
		})
		//2.2 header - align
		var alignEditor = this.header.alignEditor = $("#editor_align", this.header);
		alignEditor.change(function() { me.onChangeLayoutSetting() });

		//2.3 header - formatter
		var formatterEditor = this.header.formatterEditor = $("#editor_formatter", this.header);
		formatterEditor.change(function() { me.onChangeLayoutSetting() });

		//2.4 header - width
		var widthEditor = this.header.widthEditor = $("#width_editor", this.header);
		widthEditor.change(function() { me.onChangeLayoutSetting() });
		var typeEditor = this.header.typeEditor = $("#width_editor", this.header);
		typeEditor.change(function() { me.onChangeLayoutSetting() });
	},

	createLines: function() {
		var lines = this.logicTree.children;
		var max = lines.length;

		for (var i = 0; i < max; i++) {
			this.createOneLine(lines[i]);
		}
	},

	createOneLine: function(logic) {
		if ("Math" == logic.type) {
			this.createMathLine(logic);
		}
		else if ("IF" == logic.type) {
			this.createIFLine(logic);
		}
		else if ("ELSE" == logic.type) {
			this.createElseLine(logic);
		}
	},

	createMathLine: function(logic) {
		//1. element
		var el = logic.valuation.el = $(Formula_Template.mathLine.join(""));
		var editor = logic.valuation.editor = $("#mathEditor", el);
		// editor.prop({ disabled: true });

		//2.
		this.linkDropdown(editor);

		//3. change event
		var me = this;
		editor.change(function() {
			me.onExpressionChange.call(me);
		});

		//3. append to parent
		logic.parent.el.body.append(el);
		return result;
	},

	createIFLogic: function(parentLogic) {
		//1. clear math line
		if (this.mathLine.el) {
			this.mathLine.el.remove();
			this.mathLine = {};
		}

		//2. login tree
		this.createIFLine(parentLogic);
		this.createElseLine(parentLogic);
	},

	createIFLine: function(logic) {
		this.createLogicLine(logic, "IF");
	},

	createElseIFLine: function(logic, priorLogic) {
		this.createLogicLine(logic, "ELSE-IF", priorLogic);
	},

	createElseLine: function(logic) {
		this.createLogicLine(logic, "ELSE");
	},

	createLogicLine: function(logic, type, priorLogic) {
		//1. create element
		var el; var existsButtons;

		if ("IF" == type || "ELSE-IF" == type) {
			el = $(Formula_Template.logicIF.join(""));
			logic.condition = {};
			logic.valuation = {};
			logic.condition.editor = $("#conditionEditor", el);
			logic.valuation.editor = $("#valuationEditor", el);
			existsButtons = true;
		}
		else {
			el = logic.valuation.el = $(Formula_Template.logicELSE.join(""));
			logic.valuation.editor = $("#valuationEditor", el);
			existsButtons = false;
		}

		logic.el = el;
		el.body = $("#logic_body", el);

		//2. change event
		var me = this;

		if (logic.condition && logic.condition.editor) {
			var editor = logic.condition.editor;

			this.linkDropdown(editor);

			editor.change(function() {
				me.onExpressionChange.call(me);
			});
		}

		if (logic.valuation && logic.valuation.editor) {
			var editor = logic.valuation.editor;

			this.linkDropdown(editor);

			editor.change(function() {
				me.onExpressionChange.call(me);
			});
		}

		//3. caption
		var caption = $("#conditionCaption", el);
		caption.html(this.getLogicLabel(type));

		//4. event
		if (existsButtons) {
			var me = this;
			el.bntAddOne = $("#btn_addOne", el);
			el.bntAddOne.click(function() {
				me.createElseIFLine(parentLogic, result);
			});

			el.bntAddChild = $("#btn_addChild", el);
			el.bntAddChild.click(function() {
				me.createIFLogic(result);
			});

			el.bntDeleteOne = $("#btn_deleteOne", el);
			el.bntDeleteOne.click(function() {
				me.deleteLogic(result);
			});
		}

		//5. append to parent
		var parentLogic = logic.parent;

		if (priorLogic) {
			result.el.insertBefore(priorLogic.el);
		}
		else {
			var parentEl = parentLogic.el.body;
			parentEl.append(el);
		}

		//6. animate
		return result;
	},

	deleteLogic: function(logic) {
		var parent = logic.parent;
		var logicList = parent.children;

		//1. 只有if和else
		if (logicList.length <= 2) {
			this.initLogicBody(parent);
		}
		else {
			//1. delete from parent
			var index = logicList.indexOf(logic);
			logicList.splice(index, 1);

			//2. delete el
			logic.el.remove();
		}
	},

	initLogicBody: function(logic) {
		//1. empty parent children
		logic.children = [];

		//2. empty body
		logic.el.body.empty();

		//3. append valuation
		var valuation = $(Formula_Template.valuation.join(""));
		logic.el.body.append(valuation);
	},

	removeLogicValuation: function(logic) {
		if (!logic.el.valuation) {
			return;
		}

		logic.el.valuation.remove();
		logic.el.valuation = null;
	},

	getExpressionString: function() {
		if (logicLine) {
			var result = logicLine.expression.getString();
			return result;
		}
		if (this.activeEditor) {
			return  this.activeEditor.val();
		}

		var result = "";
		var logicTree = this.logicTree;
		var max = logicTree.children.length;

		for (var i = 0; i < max; i++) {
			var logicLine = logicTree.children[i];
			result = result + logicLine.expression.getString();
		}

		return result;
	},

	gotoMathLogic: function() {
		this.logicTree.gotoEmptyMathLogic();
		this.createLines();
	},

	gotoIFLogic: function() {
		this.logicTree.gotoEmptyIFLogic();
		this.createLines();
	},

	getLogicLabel: function(type) {
		if ("IF" == type) {
			return "如果:";
		}
		else if ("ELSE-IF" == type) {
			return "如果:";
		}
		else if ("ELSE" == type) {
			return "否则:";
		}
	},

	clear: function() {
		//1. math
		if (this.mathLine.el)  {
			this.mathLine.el.remove();
		}
		this.mathLine = {};

		//2.
		var children = this.logicTree.children;
		var max = children.length;

		for (var i = 0; i < max; i++) {
			var logic = children[i];
			logic.el.remove();
		}

		this.logicTree.children = [];
	},

	createSetting: function() {
		var me = this;

		var result = new ColumnSetting({
			owner: "formula",
			getActiveColumn: function() {
				return me.selected;
			},
			onSetCode: function(column, code) {
				me.header.codeEditor.val(code);
			},
			onSetName: function(column, name) {
				me.header.nameEditor.val(name);
			},
			onSetExpression: function(column, expression) {
				me.logicTree.parse(expression);
				me.createLines();
				me.logicTree.show();
			},
			onSetFormatter: function(column, formatter) {
				var filter = "[value='" + formatter + "']";
				var option = $(filter, me.header.formatterEditor);
				if (option) {
					option.attr("selected", "selected");
				}
			},
			onSetAlign: function(column, align) {
				var filter = "[value='" + align + "']";
				var option = $(filter, me.header.alignEditor);
				if (option) {
					option.attr("selected", "selected");
				}
			},
			onSetWidth: function(column, width) {
				var filter = "[value='" + width + "']";
				var option = $(filter, me.header.widthEditor);
				if (option) {
					option.attr("selected", "selected");
				}
			},
			onBeginSetting: function() {
				me.loading = true;

				if (this.expressionChanged) {
					me.onSaveExpression();
				}
				this.expressionChanged = false;

			},
			onEndSetting: function() {
				me.loading = false;
			}
		});

		return result;
	},

	setColumnSetting: function(sender, column, option) {
		this.selected = column;
		this.columnSetting.set(sender, column, option);
	},

	onChangeVariantCode: function() {
		if (this.loading) {
			return;
		}

		if (this.config.settingListener) {
			var value = this.header.codeEditor.val();

			this.config.settingListener.setColumnSetting(this, null, {
				code: value
			});
		}
	},

	onChangeVariantName: function() {
		if (this.loading) {
			return;
		}
		let editor = this.activeEditor;
		if (this.config.settingListener) {
			var value = this.header.nameEditor.val();
			let afterTip = {
				name: value,
				text:"[" + value + "]"
			};
			if( this.header.nameEditor.preValue) {
				let preTip = {
					name: this.header.nameEditor.preValue,
					text:"[" + this.header.nameEditor.preValue + "]"
				};
				this.updateTip(preTip, afterTip);
			}else {
				this.addOneTip(afterTip);
			}



			this.config.settingListener.setColumnSetting(this, null, {
				name: value
			});
		}
	},

	onExpressionChange: function() {
		this.columnSetting.expressionChanged = true;
	},

	onSaveExpression: function() {
		if (this.loading) {
			return;
		}

		if (this.config.settingListener) {
			var value = this.getExpressionString();
			// value = value.replace("+", "~");
			this.config.settingListener.setColumnSetting(this, null,  {
				expression: value
			});
		}
	},
	onChangeLayoutSetting: function() {
		if (this.loading) {
			return;
		}

		if (this.config.settingListener) {
			var setting = {
				align: this.header.alignEditor.val(),
				formatter: this.header.formatterEditor.val(),
				width: this.header.widthEditor.val(),
				data_type: this.header.typeEditor.val(),

			};

			this.config.settingListener.setColumnSetting(this, null, setting);
		}
	},

	setTipList: function(tipList) {
		this.tipList = tipList;

		if (this.dropdown) {
			this.dropdown.dirty = true;
		}
	},

	addOneTip: function(tip) {
		if (!tip || !tip.name) {
			return;
		}
		this.tipList[tip.name] = tip;
	},
	updateTip: function(preTip, afterTip) {
		if (!afterTip || !afterTip.name) {
			return;
		}

		this.tipList[preTip.name] = afterTip;
	},
	deleteOneTip: function(tip) {
		if (!tip || !tip.name) {
			return;
		}

		delete this.tipList[tip.name];
	},

	linkDropdown: function(editor) {
		var me = this;
		me.activeEditor = editor;
		editor.on("keydown", function(e) {
			me.onEditorKeyDown.call(me, editor, e);
		});

		editor.on("keyup", function(e) {
			me.onEditorKeyUp.call(me, editor, e);
		});
	},

	getCurrentPos: function(editor) {
		editor.focus();
		var currentPos = editor.get(0).selectionStart;
		return currentPos;
	},

	setCurrentPos: function(editor, currentPosition) {
		editor.focus();
		var currentPos = editor.get(0).selectionStart;
		if (currentPos != undefined && currentPos >= currentPosition) {
			editor.get(0).selectionStart = (currentPosition);
			editor.get(0).selectionEnd = (currentPosition);
		}

	},

	onEditorKeyDown: function(editor, e) {
		var config = this.config, Code = this.Code;
		var event = e || window.event;

		var keyCode = event.keyCode;
		if (keyCode == Code.BackSpace) {
			this.editMode = "DeleteFront";
		}
		else if (keyCode == Code.Delete) {
			this.editMode = "DeleteBack";
		}
		else if (keyCode == Code.TrigerBegin) {
			this.editMode = "ShowDropDown";
		}
		else if (keyCode == Code.Return) {
			this.editMode = "ReShowDropDown";
		}
		else {
			this.editMode = "Edit";
		}
	},

	onEditorKeyUp: function(editor, e) {
		this.activeEditor = editor;
		var editMode = this.editMode;

		if (editMode == "DeleteFront") {
			this.deleteFront(editor);
			e.preventDefault();
		}
		else if (editMode == "DeleteBack") {
			this.deleteBack(editor);
			e.preventDefault();
		}
		else if (editMode == "ShowDropDown") {
			this.showDropdown(editor);
		}
		else if (editMode == "ReShowDropDown") {
			this.reshowDropdown(editor);
		}
	},

	deleteFront: function(editor) {
		var value = editor.val();
		var pos = this.getCurrentPos(editor);

		if (pos <= 0) {
			return;
		}

		var location = this.getVariantLocation(value, pos, "toFront");
		var from = location ? location.from : pos;
		var to = location ? location.to : pos;

		value = value.substring(0, from) + value.substring(to + 1);
		editor.val(value);
	},

	deleteBack: function() {
		var value = editor.val();
		var pos = this.getCurrentPos(editor);

		if (pos >= value.length) {
			return;
		}

		var header = val.substring(pos, pos + 1);

		var location;
		if (header == this.Code.TrigerBegin) {
			location = this.getVariantLocation(value, pos, "toBack");
		}

		var from = location ? location.from : pos;
		var to = location ? location.to : pos;

		value = value.substring(0, from) + value.substring(to + 1);
		editor.val(value);
	},

	reshowDropdown: function(editor) {
		var value = editor.val();
		var pos = this.getCurrentPos(editor);

		if (pos <= 0) {
			return;
		}

		var header = val.substring(pos, pos + 1);
		if (header == this.Code.TrigerBegin) {
			this.showDropdown(editor, pos);
		}
	},

	showDropdown: function(editor, pos) {
		if (pos == undefined) {
			pos = this.getCurrentPos(editor);
		}

		if (!this.dropdown || this.dropdown.dirty) {
			this.createDropDown(editor);
		}

		this.setDropDownPosition(editor, this.dropdown.el);
		this.dropdown.el.show();
	},

	hideDropdown: function() {
		this.dropdown.el.hide();
	},

	createDropDown: function(editor) {
		if (this.dropdown) {
			this.dropdown.el.empty();
		}
		else {
			this.dropdown = {
				el: $(Formula_Template.dropdown)
			};
		}

		var tipList = this.tipList, dropdownEl = this.dropdown.el;

		if (tipList) {
			var me = this;

			for (var prop in tipList) {
				var item = tipList[prop];
				var el = $(Formula_Template.dropdownItem);
				el.html(item.name);

				el.prop("data-code", prop);
				el.click(function() {
					var code = $(this).prop("data-code");
					var item = me.tipList[code];
					me.onSelectDropdown(item);
				});

				dropdownEl.append(el);
			}
		}

		$("body").append(this.dropdown.el);
		this.dropdown.dirty = false;
		return this.dropdown;
	},
	insertMathOperator: function (item, idx) {
		var editor = this.activeEditor;
		if(!editor || !item) {
			return;
		}
		item = " "+ item +" "
		let currentPos = this.getCurrentPos(editor);
		var value = editor.val();
		// check same type tag
		let result = value.substring(0, currentPos) + item + value.substring(currentPos);
		editor.val(result);
		let nextPosition = currentPos  + item.length;
		if(idx) {
			nextPosition = currentPos  + item.length - idx - 1;
		}
		this.setCurrentPos(editor, nextPosition);
	},

	onSelectDropdown: function(item) {
		var editor = this.activeEditor;

		var pos = this.getCurrentPos(editor);
		var value = editor.val();
		var result = value.substring(0, pos - 1) + item.text + value.substring(pos + 1);
		editor.val(result);

		this.hideDropdown();
	},

	getVariantLocation: function(value, pos, direction) {
		var result = {
			from: pos,
			to: pos
		}

		if ("toBack" == direction) {
			var max = value.length;

			for (var i = pos + 1; i < max; i++) {
				var char = value.charCodeAt(i);
				if ("[" == char) {
					return result;
				}
				else if ("]" == char) {
					result.from = pos;
					result.to = i;
					return result;
				}
			}
		}
		else if ("toFront" == direction) {
			for (var i = pos - 1; i >= 0; i--) {
				var char = value[i];
				if ("]" == char) {
					return result;
				}
				else if ("[" == char) {
					result.from = i;
					result.to = pos;
					return result;
				}
			}
		}

		return result;
	},

	setDropDownPosition: function(editor, dropdown) {
		dropdown.css({
			bottom: "50px",
			left: "300px"
		});
	}

});


//*************************************
Formula_Template = {};

Formula_Template.container = [
	'<div class="formula">',
		'<div id="formula_header" class="formula-header">',
			'<span>列名:</span>',
			'<input id="editor_code" type="text" class="formula-header-code" value="" autocomplete="off"/>',
			'<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>',
			'<span>显示名称:</span>',
			'<input id="editor_name" type="text" class="formula-header-name" value="" autocomplete="off"/>',
			'<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>',
			'<span>显示格式:</span>',
			'<select id="editor_formatter">',
				'<option value="text">文本</option>',
				'<option value="percent">百分比</option>',
				'<option value="money">金额</option>',
				'<option value="decimal">数值</option>',
				'<option value="bool">是/否</option>',
			'</select>',
			'<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>',
			'<span>对齐方式:</span>',
			'<select id="editor_align">',
				'<option value="left">左对齐</option>',
				'<option value="center">居中对齐</option>',
				'<option value="right">右对齐</option>',
			'</select>',
			'<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>',
			'<span>列宽度:</span>',
			'<select id="width_editor">',
				'<option value="0.6">0.6</option>',
				'<option value="0.8">0.8</option>',
				'<option value="1">1</option>',
				'<option value="1.5">1.5</option>',
				'<option value="2.5">2.5</option>',
			'</select>',
			'<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>',
			'<span>列类型:</span>',
			'<select id="type_editor">',
			'<option value="">常规</option>',
			'<option value="customer">记账对象</option>',
			'<option value="value">记账金额</option>',
			'</select>',
		'</div>',
		'<div class="formula-body">',
			'<div id="formula_body" class="formula-body-inner">',
			'</div>',
		'</div>',
	'</div>'
];

Formula_Template.mathLine = [
    '<div id="math_body" class="math-body">',
		'<span id="mathCaption" class="math-caption">=</span>',
		'<input id="mathEditor" class="math-input" type="text" autocomplete="off" placeholder="请编辑公式"/>',
    '</div>'
];

Formula_Template.logicIF = [
	'<div class="logic">',
		'<div class="logic-condition">',
			'<div class="indicator-line"></div>',
			'<div class="indicator-if"></div>',
			'<span id="conditionCaption" class="condition-caption"></span>',
			'<input id="conditionEditor" class="logic-input-condition" type="text" autocomplete="off"/>',
			'<div class="logic-btn-group">',
				'<div id="btn_addOne" class="logic-btn">+&nbsp;同级</div>',
				'<div id="btn_addChild" class="logic-btn">+&nbsp;下级</div>',
				'<div id="btn_deleteOne" class="logic-btn">-&nbsp;删除</div>',
			'</div>',
		'</div>',
		'<div id="logic_body" class="logic-body">',
			'<div class="indicator-line"></div>',
			'<div id="valuation_body" class="valuation-body">',
				'<input id="valuationEditor" class="logic-input-valuation" type="text" autocomplete="off"/>',
			'</div>',
		'</div>',
    '</div>'
];

Formula_Template.logicELSE = [
	'<div class="logic">',
		'<div id="logic_body" class="logic-condition">',
			'<div class="indicator-else"></div>',
			'<span id="conditionCaption" class="condition-caption"></span>',
			'<input id="valuationEditor" class="logic-input-valuation" type="text" autocomplete="off"/>',
		'</div>',
    '</div>'
];

Formula_Template.valuation = [
	'<div class="indicator-line"></div>',
	'<div id="valuation_body" class="valuation-body">',
		'<input id="valuationEditor" type="text" autocomplete="off"/>',
	'</div>',
];

Formula_Template.dropdown = "<ul class='tips' style='display:none;'></ul>";

Formula_Template.dropdownItem = "<li class='tips-item'></li>";