2010-08-10 53 views
5

Tôi đang cố tạo một vùng văn bản tự động thụt lề và cho đến nay nó hoạt động với mã sau đây. Vấn đề mà tôi đang gặp là tôi hiện đang ngăn chặn hành động mặc định khi nhấn enter để tính toán các tab trong dòng và sau đó chèn dòng mới sau đó.Diện tích văn bản "Thông minh" tự động thụt lề

Tác phẩm này, nhưng tôi muốn có hành động mặc định của vùng văn bản, nếu bạn nhấn giữ, nó sẽ không di chuyển vùng văn bản cho đến khi dấu mũ chạm vào hàng dưới cùng, sau đó thanh cuộn vẫn giữ nguyên ở hàng dưới cùng. Mã hiện tại bên dưới giữ dấu mũ trong trường nhìn nếu được sử dụng ở bất kỳ vị trí nào trong vùng văn bản, nhưng nó làm nội dung phía trên dấu mũ để cuộn lên, đó là một sự thỏa hiệp vì dấu mũ không còn biến mất nữa. Nếu không có giải pháp nào khác, điều này sẽ hoạt động tốt, nhưng tôi hy vọng có những ý tưởng khác.

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; 

EDIT Như một bản cập nhật, để xóa đi bất kỳ sự nhầm lẫn, tôi đang cố gắng để tạo ra một textbox kiểu IDE, ví dụ như vậy trong hầu hết các IDE nếu bạn gõ như sau

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

Tôi muốn nó đưa bạn đến cùng một khoảng cách tab từ đường viền bên trái dưới dạng "Nội dung mẫu" để giữ cho mã của bạn dễ đọc hơn. Tôi hiện đang có chức năng đó nhưng vấn đề là tôi đang chặn khóa nhập, có nghĩa là tôi phải cung cấp chức năng đó. Tôi gặp khó khăn khi sao chép chính xác chức năng của việc không cuộn hộp văn bản cho đến khi con trỏ chạm vào đường viền dưới cùng. Vì vậy, nếu bạn đã giữ để nhập ở trên cùng của textarea, con trỏ chỉ cần di chuyển xuống textarea, di chuyển bất kỳ văn bản với nó cho đến khi nó chạm vào biên giới phía dưới, và sau đó scrollbar cho textarea sẽ theo con trỏ. Có lý?

EDIT 2thẻ cập nhật để chỉ ra code đang với PHP

Tôi đã làm việc về vấn đề này trong khi bài này đã được ngồi. Tôi nghĩ rằng một tùy chọn khác mà tôi sẽ khám phá khi tôi có cơ hội thay vì ngăn chặn nhập chỉ cho phép hành động mặc định nhấn enter và đọc chuỗi từ lastIndexOf('\n')-1 đến \n gần đây nhất đối với bất kỳ \t nào. Tôi nghĩ rằng sẽ cho tôi chuỗi mà tôi đang tìm kiếm, nhưng không làm rối loạn hành vi của văn bản. Sẽ cập nhật lại sau khi thử nghiệm.

EDIT 3 Đã giải quyết, như bản cập nhật trước của tôi, tôi quyết định quét chuỗi sau khi nhấn phím, giữ nguyên hành vi tự nhiên (phần thay đổi được thêm bên dưới cho những người quan tâm) và vấn đề duy nhất thực sự là bạn giữ nhập, nó sẽ không đếm thụt đầu dòng từ nguồn gốc của báo chí nhập, đó là tốt của tôi. Tôi sẽ cung cấp cho một trong những http://stackoverflow.com/users/15066/matyr'>matyr, mặc dù tôi đã tìm ra trước khi ông trả lời ông vẫn là gần nhất.

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); 

Trả lời

2

Tôi muốn có hành động mặc định của textarea

Làm thế nào về ràng buộc để keyup thay vì keydown/keypress và chèn các tab sau khi ngắt dòng bản địa?

thanh cuộn ở lại với caret ở hàng dưới cùng

Bạn có thể duy trì vị trí cuộn bằng cách khôi phục 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) 
+0

Duy trì vị trí cuộn không phải là vấn đề, nó cho phép con trỏ tiếp tục đến cuối của vùng văn bản trước khi theo dõi nó với mỗi dòng mới.Tôi sẽ cố gắng sử dụng keyup thay vì keydown theo lần cập nhật gần đây nhất của tôi – Robert

+0

nếu bạn sử dụng KEYUP có nghĩa là nó sẽ kích hoạt tất cả các nút bấm, thực tế chúng ta cần đôi khi để giữ một nút để có nhiều sự kiện.Trong trường hợp đó KEYDOWN là tốt hơn.Đó là sự kiện KEYDOWN cháy trước khi ký tự textarea cập nhật để bạn muốn sử dụng el.keydown (function (e) {setTimeout (function (e) {/ * HÀNH ĐỘNG KEYDOWN CỦA BẠN * /}, 1)}); – kami

1

Bạn đã bao giờ nhận thấy cách xử lý văn bản của Stack Overflow? Nếu bạn nhập:

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

Lúc đầu, sẽ không có gì xảy ra. Sau đó, khi bạn thụt lề (bằng cách gõ hoặc bằng cách bấm vào nút 101010), nó sẽ đặt một nền tảng khác trên mã. Sau đó,, sau khi bạn chờ một lát, cú pháp sẽ tô màu mã. Nhưng nếu bạn bắt đầu gõ lại, nó sẽ trở lại màu đen/trắng.

Tôi nghĩ rằng một phương pháp tương tự có thể phù hợp với bạn.Thay vì cố gắng liên kết mọi thứ với sự kiện nhấn phím, bạn nên làm gì:

  1. Hookup một sự kiện onKeySomething bình thường, nhưng đừng tìm "enter"; sau mỗi lần nhấn phím:

    1A. Đặt một số biến số toàn cục (ví dụ: bộ đếm thời gian) thành Ngày mới();

    1B. setTimeout (X, timeoutFunction) trong đó X là dài nhưng bạn muốn đợi sau khi người dùng ngừng nhập

  2. Tạo timeoutFunction; chức năng này nên kiểm tra biến "timer" toàn cục và nếu Date() - timer> X mới kích hoạt hàm realFunction()

  3. actualFunction sau đó có thể phân tích nội dung của văn bản, những thứ thụt lề mà bạn thích và không có gì làm gián đoạn luồng bình thường Những điều cần thiết cho người dùng

Tôi biết điều này không hoàn toàn là cách thực hiện của IDE, nhưng với những hạn chế của JS và web, đó có thể là cách tiếp cận tốt nhất cho bạn.

+0

Mục đích của dự án là để có thể mã trực tiếp trong vùng văn bản và làm sạch mã sau khi người dùng hoàn tất. – Robert

+0

Làm rõ, * không dọn sạch mã sau khi người dùng nhập xong. Tôi thích thời gian thực như một IDE. Luôn luôn có một cách để làm một cái gì đó, bạn chỉ cần có đủ sáng tạo. Tôi chắc chắn tôi sẽ tìm cách cuối cùng;) – Robert

+0

Vâng, tôi không nói rằng cách tiếp cận của bạn là không thể, nhưng ... bạn phải ghi nhớ rằng hầu hết người dùng không chạy Google Chrome với lõi tứ/12 hợp đồng biểu diễn RAM; trên các hệ thống bình thường chạy IE/Firefox, hiệu suất JS là kinda lame. Vì vậy, ngay cả khi bạn tìm thấy một giải pháp "hoàn hảo", nó vẫn có thể sẽ rất đáng thất vọng đối với hầu hết người dùng của bạn vì độ trễ hiệu suất JS.(PS Nếu bạn có thể dựa vào phần cứng tốt + Chrome, không bao giờ). Nói cách khác, tôi chắc chắn rằng những người SO sẽ làm cho văn bản của họ phản ứng nhanh hơn nếu họ có thể ... nhưng họ chưa (vì những hạn chế này). – machineghost

0

Làm thế nào về phân lớp hộp văn bản và xử lý thủ công WndProc? Điều này giúp bạn kiểm soát tốt hơn nhiều hạt, và sẽ giải quyết lặp lại phím typematic (KeyPress và các sự kiện tương tự chỉ kích hoạt một lần khi bạn giữ phím).

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); 
     } 
    } 
} 
+0

Tôi nên xây dựng, điều này đang được thực hiện trong Javascript/PHP. – Robert

+0

Tại sao một người nào đó bỏ phiếu cho tôi? Nó không chính xác rõ ràng từ bài viết gốc. :( –

Các vấn đề liên quan