package org.netxilia.server.js.editors;
import static org.netxilia.server.js.NX.nx;
import static org.netxilia.server.jslib.NetxiliaGlobal.$;
import static org.stjs.javascript.Global.$map;
import static org.stjs.javascript.Global.setTimeout;
import org.netxilia.server.js.Bounds2;
import org.netxilia.server.js.Cell;
import org.netxilia.server.js.CellRange;
import org.netxilia.server.jslib.CaretPosition;
import org.netxilia.server.jslib.NetxiliaJQuery;
import org.stjs.javascript.Array;
import org.stjs.javascript.Map;
import org.stjs.javascript.RegExp;
import org.stjs.javascript.dom.Element;
import org.stjs.javascript.functions.Callback0;
import org.stjs.javascript.jquery.Event;
import org.stjs.javascript.jquery.EventHandler;
public class TextEditor implements Editor {
private Map<String, Object> params;
private NetxiliaJQuery editorElement;
private EditingContext context;
public TextEditor(EditingContext context, Map<String, Object> params) {
this.params = params;
this.context = context;
}
@Override
public String value() {
return this.editorElement != null ? (String) this.editorElement.val() : null;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void edit(Cell cell, Bounds2 pos, String value) {
final TextEditor that = this;
this.editorElement = this.context.elements.$get("default-editor");
if (this.editorElement == null) {
this.editorElement = $(
"<textarea id='default-editor' autocapitalize='off' class='editor-visible-index'></textarea>")
.appendTo(this.context.container);
// enlarge editor as needed
this.editorElement.keydown(new EventHandler() {
@Override
public boolean onEvent(Event ev, Element THIS) {
if (that.context.valueChanged != null && ev.keyCode != 13) {
final NetxiliaJQuery $elm = $(THIS);
setTimeout(new Callback0() {
@Override
public void $invoke() {
that.context.valueChanged.$invoke((String) $elm.val());
}
}, 1);
}
if (ev.keyCode < 32) {
return true;
}
if ($(THIS).height() < THIS.scrollHeight) {
$(THIS).height(THIS.scrollHeight);
}
return false;
}
});
this.context.elements.$put("default-editor", this.editorElement);
}
int pwidth = this.editorElement.parent().width();
this.editorElement.css($map("top", pos.top, "left", pos.left, "width",
org.stjs.javascript.Math.min(pos.width + 150, pwidth - pos.left), "height", pos.height));
this.editorElement.attr("minHeight", "" + pos.height);
// cell->editor
if (value != null) {
this.editorElement.val(value);
} else {
this.editorElement.val(cell.getValue());
}
setTimeout(new Callback0() {
@Override
public void $invoke() {
if (that.editorElement.height() < that.editorElement.get(0).scrollHeight) {
that.editorElement.height(that.editorElement.get(0).scrollHeight);
}
that.editorElement.putCursorAtEnd();
}
}, 1);
}
@Override
public void setCaptureSelection(CellRange selection) {
// TODO modify selection also
int cursor = this.editorElement.caret().start;
String v = (String) this.editorElement.val();
String leftString = v.substring(0, cursor);
RegExp endWithRefRegex = new RegExp(nx.utils.regexRef.source + "$");
final int keepPos;
Array<String> m = endWithRefRegex.exec(leftString);
if (m != null) {
// replace the matching part with the new reference
this.editorElement.val(v.substring(0, cursor - m.$get(0).length()) + selection.start.ref(false)
+ v.substring(cursor));
keepPos = cursor - m.$get(0).length() + selection.start.ref(false).length();
} else {
// add the new reference
this.editorElement.val(v.substring(0, cursor) + selection.start.ref(false) + v.substring(cursor));
keepPos = cursor + selection.start.ref(false).length();
}
this.editorElement.caret(new CaretPosition() {
{
start = keepPos;
end = keepPos;
}
});
if (this.context.valueChanged != null) {
this.context.valueChanged.$invoke((String) this.editorElement.val());
}
}
@Override
public void show(boolean show) {
if (show) {
this.editorElement.show();
this.editorElement.focus();
} else {
this.editorElement.hide();
}
}
}