单行 Ace 编辑器
Single line Ace editor
我正在尝试设置一个只有一行文本的 Ace 编辑器。
这个想法是模仿 <input type="text">
框的行为,但使用语法着色:
目前,如果用户在编辑器中按下 Enter
,它会创建一个新行:
所以我的问题是:
如何设置 Ace 只允许一行,就像标准文本输入框一样?
以下是我到目前为止的尝试,以及未成功的原因。
如果 e.lines.length > 1
在 change
上调用 editor.undo()
问题是,change
在 实际更改应用于增量之前 被触发,因此 undo()
在这里不起作用(或它涉及之前的增量)
取消 keypress
如果 Event.which = 13
它有点用但很脏,而且它不处理粘贴多行文本的情况,所以我们还需要处理 paste
事件 - 这将成为这个解决方案甚至更脏。我也非常有信心会有更多的边缘情况需要考虑。
尝试在on("change", function(e) { ... })
中"empty"e
比如在回调函数中说e = {}
,前提是e
只是对实际对象的引用。一点效果都没有。
试图在 Ace 编辑器中找到一个内置参数来做到这一点
还没有成功找到这样的参数...
出于某种原因,e.preventDefault
和 e.stopPropagation
都无法在更改事件处理程序中工作。但是你可以做查找替换。
参见fiddle:http://jsfiddle.net/vittore/3rLfdtxb/
var editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.getSession().setMode("ace/mode/javascript");
editor.setFontSize(30)
editor.getSession().on('change', function(e) {
console.log(e)
if (e.data.text.charCodeAt(0) === 10 && e.data.action == "insertText") {
console.log('cancel event')
//e.preventDefault() // doesnt work
//e.stopPropagation() // doesnt work
editor.find(String.fromCharCode(10))
editor.replaceAll(''); // this work
}
})
您甚至可以从处理程序中删除 if
语句并替换任何更改的换行符,无论如何。
当你在更改中查找替换时,你得到了从光标到所选行末尾的行。为了在使用之后取消选择它:
editor.selection.clearSelection()
您可以使用以下代码使编辑器的行为类似于输入类型="text"(主要取自https://github.com/ajaxorg/ace/blob/v1.2.0/demo/kitchen-sink/layout.js#L103)
var el = document.getElementById("textbox")
var editor = ace.edit(el);
editor.setOptions({
maxLines: 1, // make it 1 line
autoScrollEditorIntoView: true,
highlightActiveLine: false,
printMargin: false,
showGutter: false,
mode: "ace/mode/javascript",
theme: "ace/theme/tomorrow_night_eighties"
});
// remove newlines in pasted text
editor.on("paste", function(e) {
e.text = e.text.replace(/[\r\n]+/g, " ");
});
// make mouse position clipping nicer
editor.renderer.screenToTextCoordinates = function(x, y) {
var pos = this.pixelToScreenCoordinates(x, y);
return this.session.screenToDocumentPosition(
Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)),
Math.max(pos.column, 0)
);
};
// disable Enter Shift-Enter keys
editor.commands.bindKey("Enter|Shift-Enter", "null")
#textbox {
font-size: 30px;
border:solid 2px gray;
}
body{
background: #161619;
padding: 40px 20px
}
<script src="https://ajaxorg.github.io/ace-builds/src/ace.js"></script>
<div id=textbox>var a = 1</div>
现有的两个答案都对我的工作很有帮助,但我仍然遇到了一些我必须解决的问题(有些显然是由于 api 更改)。这是对我有用的两个答案的组合。
注意,当您 运行 这些片段或 jsFiddle 时,CORS 检查将阻止 worker 加载,只是因为示例 "works" 并不意味着它在集成到您的项目中时都能正常工作。
另请注意...这是使用挂钩的反应代码,但基本代码应该适用。
它还使用来自
的调整大小代码
const editDiv = useRef<HTMLDivElement>(null);
useEffect(() => {
if (editing) {
if (!editor && editDiv.current) {
editDiv.current.textContent = value;
const ed = ace.edit(editDiv.current);
ed.setOptions({
maxLines: 1,
autoScrollEditorIntoView: true,
highlightActiveLine: false,
printMargin: false,
showGutter: false,
enableLiveAutocompletion: true,
enableBasicAutocompletion: true,
enableSnippets: false,
mode: "ace/mode/javascript",
theme: "ace/theme/tomorrow_night_eighties"
});
ed.commands.bindKey(
"Up|Ctrl-P|Down|Ctrl-N|PageUp|PageDown",
"null"
);
ed.commands.addCommand({
name: "SaveOnEnter",
bindKey: {
win: "Enter",
mac: "Enter",
sender: "editor|cli"
},
exec: () => {
setValue(ed.getValue());
// Handle new value;
}
});
ed.on("paste", e => {
e.text = e.text.replace(/[\r\n]+/g, " ");
});
setEditor(ed);
ed.getSession().on("change", e => {
if (e.action == "insert" && ed.session.getValue().includes("\n")) {
setTimeout(() => {
// doing a replaceAll during a change event causes issues in the
// worker, so we'll queue up the change
ed.find(String.fromCharCode(10));
ed.replaceAll("");
ed.selection.clearSelection();
}, 0);
}
});
ed.renderer.on("beforeRender", (e, renderer) => {
const rSession = renderer.session;
const text = rSession.getLine(0);
const charCount = rSession.$getStringScreenWidth(text)[0];
const width =
Math.max(charCount, 2) * renderer.characterWidth + // text size
2 * renderer.$padding + // padding
2 + // little extra for the cursor
0; // add border width if needed
renderer.container.style.width = width + "px";
renderer.onResize(false, 0, width, renderer.$size.height);
});
ed.setWrapBehavioursEnabled(false);
ed.session.setUseWrapMode(false);
ed.focus();
}
} else {
if (editor) {
editor.renderer.on("beforeRender", () => {});
editor.destroy();
setEditor(undefined);
}
}
}, [editing]);
return <div ref={editDiv} style={{ width: "1em", height: "1.2em" }} />;
尝试在 setOptions
属性 中将 maxLines
设置为 1
。
我使用 react-ace
版本 9.2.0
。
我将其用作 optional/configurable 行为,并在包装器组件上公开了 属性:
maxLines={this.props.singleLine ? 1 : undefined}
我正在尝试设置一个只有一行文本的 Ace 编辑器。
这个想法是模仿 <input type="text">
框的行为,但使用语法着色:
目前,如果用户在编辑器中按下 Enter
,它会创建一个新行:
所以我的问题是:
如何设置 Ace 只允许一行,就像标准文本输入框一样?
以下是我到目前为止的尝试,以及未成功的原因。
如果
在e.lines.length > 1
change
上调用editor.undo()
问题是,
change
在 实际更改应用于增量之前 被触发,因此undo()
在这里不起作用(或它涉及之前的增量)取消
keypress
如果Event.which = 13
它有点用但很脏,而且它不处理粘贴多行文本的情况,所以我们还需要处理
paste
事件 - 这将成为这个解决方案甚至更脏。我也非常有信心会有更多的边缘情况需要考虑。尝试在
中"empty"on("change", function(e) { ... })
e
比如在回调函数中说
e = {}
,前提是e
只是对实际对象的引用。一点效果都没有。试图在 Ace 编辑器中找到一个内置参数来做到这一点
还没有成功找到这样的参数...
出于某种原因,e.preventDefault
和 e.stopPropagation
都无法在更改事件处理程序中工作。但是你可以做查找替换。
参见fiddle:http://jsfiddle.net/vittore/3rLfdtxb/
var editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.getSession().setMode("ace/mode/javascript");
editor.setFontSize(30)
editor.getSession().on('change', function(e) {
console.log(e)
if (e.data.text.charCodeAt(0) === 10 && e.data.action == "insertText") {
console.log('cancel event')
//e.preventDefault() // doesnt work
//e.stopPropagation() // doesnt work
editor.find(String.fromCharCode(10))
editor.replaceAll(''); // this work
}
})
您甚至可以从处理程序中删除 if
语句并替换任何更改的换行符,无论如何。
当你在更改中查找替换时,你得到了从光标到所选行末尾的行。为了在使用之后取消选择它:
editor.selection.clearSelection()
您可以使用以下代码使编辑器的行为类似于输入类型="text"(主要取自https://github.com/ajaxorg/ace/blob/v1.2.0/demo/kitchen-sink/layout.js#L103)
var el = document.getElementById("textbox")
var editor = ace.edit(el);
editor.setOptions({
maxLines: 1, // make it 1 line
autoScrollEditorIntoView: true,
highlightActiveLine: false,
printMargin: false,
showGutter: false,
mode: "ace/mode/javascript",
theme: "ace/theme/tomorrow_night_eighties"
});
// remove newlines in pasted text
editor.on("paste", function(e) {
e.text = e.text.replace(/[\r\n]+/g, " ");
});
// make mouse position clipping nicer
editor.renderer.screenToTextCoordinates = function(x, y) {
var pos = this.pixelToScreenCoordinates(x, y);
return this.session.screenToDocumentPosition(
Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)),
Math.max(pos.column, 0)
);
};
// disable Enter Shift-Enter keys
editor.commands.bindKey("Enter|Shift-Enter", "null")
#textbox {
font-size: 30px;
border:solid 2px gray;
}
body{
background: #161619;
padding: 40px 20px
}
<script src="https://ajaxorg.github.io/ace-builds/src/ace.js"></script>
<div id=textbox>var a = 1</div>
现有的两个答案都对我的工作很有帮助,但我仍然遇到了一些我必须解决的问题(有些显然是由于 api 更改)。这是对我有用的两个答案的组合。
注意,当您 运行 这些片段或 jsFiddle 时,CORS 检查将阻止 worker 加载,只是因为示例 "works" 并不意味着它在集成到您的项目中时都能正常工作。
另请注意...这是使用挂钩的反应代码,但基本代码应该适用。
它还使用来自
const editDiv = useRef<HTMLDivElement>(null);
useEffect(() => {
if (editing) {
if (!editor && editDiv.current) {
editDiv.current.textContent = value;
const ed = ace.edit(editDiv.current);
ed.setOptions({
maxLines: 1,
autoScrollEditorIntoView: true,
highlightActiveLine: false,
printMargin: false,
showGutter: false,
enableLiveAutocompletion: true,
enableBasicAutocompletion: true,
enableSnippets: false,
mode: "ace/mode/javascript",
theme: "ace/theme/tomorrow_night_eighties"
});
ed.commands.bindKey(
"Up|Ctrl-P|Down|Ctrl-N|PageUp|PageDown",
"null"
);
ed.commands.addCommand({
name: "SaveOnEnter",
bindKey: {
win: "Enter",
mac: "Enter",
sender: "editor|cli"
},
exec: () => {
setValue(ed.getValue());
// Handle new value;
}
});
ed.on("paste", e => {
e.text = e.text.replace(/[\r\n]+/g, " ");
});
setEditor(ed);
ed.getSession().on("change", e => {
if (e.action == "insert" && ed.session.getValue().includes("\n")) {
setTimeout(() => {
// doing a replaceAll during a change event causes issues in the
// worker, so we'll queue up the change
ed.find(String.fromCharCode(10));
ed.replaceAll("");
ed.selection.clearSelection();
}, 0);
}
});
ed.renderer.on("beforeRender", (e, renderer) => {
const rSession = renderer.session;
const text = rSession.getLine(0);
const charCount = rSession.$getStringScreenWidth(text)[0];
const width =
Math.max(charCount, 2) * renderer.characterWidth + // text size
2 * renderer.$padding + // padding
2 + // little extra for the cursor
0; // add border width if needed
renderer.container.style.width = width + "px";
renderer.onResize(false, 0, width, renderer.$size.height);
});
ed.setWrapBehavioursEnabled(false);
ed.session.setUseWrapMode(false);
ed.focus();
}
} else {
if (editor) {
editor.renderer.on("beforeRender", () => {});
editor.destroy();
setEditor(undefined);
}
}
}, [editing]);
return <div ref={editDiv} style={{ width: "1em", height: "1.2em" }} />;
尝试在 setOptions
属性 中将 maxLines
设置为 1
。
我使用 react-ace
版本 9.2.0
。
我将其用作 optional/configurable 行为,并在包装器组件上公开了 属性:
maxLines={this.props.singleLine ? 1 : undefined}