“智能”文本区域自动缩进

时间:2010-08-10 00:57:29

标签: php javascript jquery

我正在尝试创建一个自动缩进文本区域,到目前为止它可以使用以下代码。我遇到的问题是我目前正在阻止按Enter键的默认操作,以便计算行中的选项卡,然后再插入换行符。

这样可行,但是我希望得到textarea的默认操作,因为如果按住enter键,它就不会滚动textarea直到插入符号触及底行,然后滚动条会保留为插入符号底行。如果在textarea的任何地方使用,下面的当前代码将插入符号保持在视野范围内,但它会使插入符号上方的内容向上滚动,这是一种妥协,因为插入符号不再消失。如果没有其他解决方案,这将工作正常,但我希望还有其他想法。

    var start = this.selectionStart-1;
    var end = this.selectionEnd;
    var sT = this.scrollTop;
    var sH = this.scrollHeight;
    var vH = $(this).height();

    var x = (sH - sT) - vH;

    // Check if hitting enter on the first line as no newline will be found
    if (this.value.lastIndexOf('\n',start)==-1)
     var startSubstr = 0;
    else 
     var startSubstr = this.value.lastIndexOf('\n',start)+1;

    var endFirst = end - startSubstr;

    var valueToScan = this.value.substr(startSubstr,endFirst);
    var count = 0;

    // Count only \t at the beginning of the line, none in the code   
    while (valueToScan.indexOf('\t')!=-1) {
     if (valueToScan.indexOf('\t')!=0)
      break;
     count++;
     valueToScan = valueToScan.substr(valueToScan.indexOf('\t')+1);
    }

    // Command to isert the newline, and then add the \t's found in previously  
    $(this).insertAtCaret('\n');
    for (var i=0;i<count;count--) {
     $(this).insertAtCaret('\t');
    }  

    var sH = this.scrollHeight;
    this.scrollTop = (sH - x) - vH;

修改 作为更新,为了消除任何混淆,我正在尝试创建一个IDE样式的文本框,例如在大多数IDE中,如果键入以下内容

function example(whatever) {
     Example Stuff // And then hit enter here

我希望它能够将您带到左边框的相同标签距离作为“示例资料”,以便让您的代码更易于阅读。我目前有这个功能,但问题是我正在拦截回车键,这意味着我必须提供该功能。我很难复制不滚动文本框的确切功能,直到光标到达底部边框。因此,如果你要在textarea的顶部按住enter键,光标只会向下滚动textarea,用它移动任何文本直到它到达底部边框,然后textarea的滚动条将跟随光标。有意义吗?

编辑2 更新了标签以表明代码是使用PHP

这篇文章一直在讨论,我一直在努力。我认为,当我有机会时,我将要探索的另一个选项是阻止输入,只允许默认操作点击输入并从lastIndexOf('\n')-1读取字符串到最近的\n \t。我想这会给我一些我正在寻找的字符串,但不会弄乱textarea的行为。测试后会再次更新。

编辑3 已解决,根据我之前的更新,我决定在按下按键后扫描字符串,保留自然行为(下面为感兴趣的人添加了更改的部分)以及真正的唯一问题遗留的是,如果你按住回车键,它将不计算来自输入印刷机原点的缩进,这对我来说没问题。我打算把这个给http://stackoverflow.com/users/15066/matyr'>matyr,虽然我在回答之前确实知道他仍然是最接近的。

if (this.value.lastIndexOf('\n',start-2)==-1) {
 var startSubstr = 0;
} else {
 var startSubstr = this.value.lastIndexOf('\n',start-1)+1;
}    
var valueToScan = this.value.substr(startSubstr,start);

4 个答案:

答案 0 :(得分:2)

  

我想拥有textarea的默认动作

如何绑定到keyup而不是keydown / keypress并在原生换行符后插入标签?

  

滚动条在底行留下插入符号

您可以通过恢复scrollTop来保留滚动位置。

<!DOCTYPE html>
<title>autoindent example</title>
<textarea id="TA" rows="8"></textarea>
<script>
document.getElementById('TA').addEventListener('keyup', function(v){
  if(v.keyCode != 13 || v.shiftKey || v.ctrlKey || v.altKey || v.metaKey)
    return;
  var val = this.value, pos = this.selectionStart;
  var line = val.slice(val.lastIndexOf('\n', pos - 2) + 1, pos - 1);
  var indent = /^\s*/.exec(line)[0];
  if(!indent) return;
  var st = this.scrollTop;
  this.value = val.slice(0, pos) + indent + val.slice(this.selectionEnd);
  this.selectionStart = this.selectionEnd = pos + indent.length;
  this.scrollTop = st;
}, false);
</script>
<p>(not considering IE here)

答案 1 :(得分:1)

你有没有注意到Stack Overflow textareas如何处理代码?如果输入:

function example(whatever) {
    Example Stuff // And then hit enter here
}

起初,什么都不会发生。然后,当您缩进(通过键入或单击101010按钮)时,它会在代码上添加不同的背景。 然后,等了一会儿之后,语法为代码着色。但如果你再次开始打字,它会回到黑/白。

我认为类似的方法可能对您有用。你应该做的是:

,而不是试图将所有内容与enter keypress事件联系起来
  1. 连接正常的onKeySomething事件,但不要只查找“enter”;每次按键后:

    1A。将一些全局变量(例如,计时器)设置为新的Date();

    1B。 setTimeout(X,timeoutFunction)其中X在用户停止输入后要等待很长时间

  2. 创建timeoutFunction;此函数应检查全局“计时器”变量,如果是新的Date() - 计时器&gt; X触发actualFunction()

  3. actualFunction可以解析textarea的内容,缩进你喜欢的东西,没有任何东西可以打断用户的正常流程

  4. 我知道这不是“真正的”IDE的表现,但考虑到JS和网络的局限性,它可能是最好的方法。

答案 2 :(得分:0)

如何对文本框进行子类化并手动处理WndProc?这样可以获得更细粒度的控制,并且可以解决键控键重复(KeyPress和类似事件只有在按住键时才会触发)。

public class MyTextBox : System.Windows.Forms.TextBox
{
    protected override void WndProc(ref Message m)
    {
        // Let the O/S handle the key first
        base.WndProc(ref m);

        // Then, if it's the return key, append tabs
        int numTabs = 3;                 // TODO: insert your own value here
        const int WM_CHAR = 0x0102;
        if(m.Msg == WM_CHAR && (char)m.WParam == '\r')
        {
            m.WParam = new IntPtr('\t'); // Recycle m since base is done with it
            for (int i = 0; i < numTabs; i++)
                WndProc(ref m);
        }
    }
}

答案 3 :(得分:0)

我知道这不是一个直接的答案,但是你可以在网上看到一些可以帮助你实现这个的例子。

http://jsfiddle.net
http://teddevito.com/demos/textarea.html
http://thelackthereof.org/JQuery_Autoindent

如果我有更多时间,我肯定会试一试,但遗憾的是我没有。