Solved

Undo and Only Allow Deletes in Textarea

Posted on 2003-11-18
8
482 Views
Last Modified: 2008-06-02
Delete Only

I need to create a text area that will provide very limited editing capabilities to our users.  The textarea will come prefilled with text.  I want to give users the ability to ONLY delete text from the textarea, not to add any text.  I have generally figured out how to do this, by disabling all keys except delete/backspace and the arrow keys.  One thing I have not been able to turn off, however, it the right-mouse-click paste feature, which will paste text, notwithstanding the disabling of other keys.  I want the paste disabled JUST for the textarea (there will be other stuff on the page).

Undo

Related to this, I want to give users the ability to undo (redo is not important) any deletions they have made, such as by including an undo button under the textarea.  (there can be an unlimited number of undos).  However, I have not been able to figure out how to do this.
0
Comment
Question by:msalamon
8 Comments
 
LVL 1

Expert Comment

by:Witchazel
ID: 9774986
<textarea
  onbeforepaste=event.returnValue=false
  onpaste=event.returnValue=false
>HIHI</textarea>

no more pasten.  killing the keys is probable your best bet too.

-w
0
 
LVL 1

Expert Comment

by:Witchazel
ID: 9775019
undoes

<script>
var versions = new Array();
</script>

<textarea id=youcannottypetome
  onbeforepaste=event.returnValue=false
  onpaste=event.returnValue=false
  onkeydown=(hoping you killed all keys on keydown)
  onkeyup=versions[versions.length]=this.value
  oncut=versions[versions.length]=this.value
>HIHI</textarea>
<button onclick="youcannottypetome.value=versions[versions.length-1];versions.length=versions.length-1"
>HIHI</button>
0
 

Author Comment

by:msalamon
ID: 9780216
Thanks.  The paste restriction worked great.  However, I have a few concerns about the undo.

First, the restriction on editing that I need, that you can only delete, does not seem to work if you fully disable onkeydown, which you recommended.  I am not an expert on javascript in any way, but I was applying the same function:

function disableNonDelete()
{

      e = event;



      if(e.keyCode == 8 || e.keyCode == 46 || (e.keyCode >= 37 && e.keyCode <=40))

            return true;

      else

            return false;

}


on each of the following (although all may not be necessary):

onKeyDown="return disableNonDelete();"
onKeyPress="return disableNonDelete();"
onKeyUp="return disableNonDelete();"
onChange="return disableNonDelete();"

How can I both preserve the ability to delete with the delete/backspace key and include ALL deletes (using either delete, backspace, control-x or right-mouse-cut) in the undo functionality.

Second, my disable delete function does not seem to be able to allow control-x for deleting.  Since this is a key combination, as soon as the control key is hit, the function won't wait for the -x to be hit as well.  Do you know how I can get control-x to work too (along with delete, backspace, and the arrows)?

Third, if you hit undo and there is nothing in the array, then the textarea gets the text "undefined". How do I disable the undo button when the array.length = 0?

Fourth, the Array holds the entire contents of the text area, which in some cases may be 20+ pages.  If we store a copy of the text every time a single letter is deleted, the array is going to get VERY full  What I was hoping (but couldn't figure out how), was to use the document.getSection() methods of javascript to work.  I was hoping that each time you either selected and then deleted text, or just deleted text with a key stroke, that I could store the starting point of where the delete happened and the text deleted, and put that into the undo array.  Then, each time you hit undo, it would take the last deletion and insert the text at the point where it was deleted, updating the text in the textarea.  this would greatly reduce the text stored in the array.  A solution like that would be great!

0
 
LVL 1

Expert Comment

by:Witchazel
ID: 9781146
oopsie wrong event for the control+X and mouse cut ; this will be better (oncut should be onbeforecut :)


<script>
var versions = new Array();

function undo() {
     if(version.length>0) {
          youcannottypetome.value=versions[versions.length-1];
          versions.length=versions.length-1;
     }
}

function keydow() {
    switch(event.keyCode) {
        case 88:  case 67:    // x and c (not sure if you want c because that is copy not really delete)
            if(event.ctrlKey) return;       // if control x or control c go about yer business         break;
        case 8:  case 46:
            return;             // if del or backspace  go about your business
        break;
    }
    event.returnValue = false;       // everything else is canceled
}
</script>

<textarea id=youcannottypetome
  onbeforepaste=event.returnValue=false
  onpaste=event.returnValue=false
  onkeydown=keydown()
  onkeyup=versions[versions.length]=this.value
  onbeforecut=versions[versions.length]=this.value
>HIHI</textarea>

<button onclick="youcannottypetome.value onclick=undo()>HIHI</button>

note if you allow them to use copy/control c you need to add
  onbeforecopy=versions[versions.length]=this.value


-w


0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 1

Expert Comment

by:Witchazel
ID: 9781327
for the selection area the hardest part you are going to have is finding where you are in the textarea, i think ns6 has a cursorlocation call but ie doesnt.

here is the psudo of what you need to do

on before delete key or backspace key

var selection = document.selection.createRange().duplicate();  // get range, this will be blank (del not done)
selection.moveStart("character",-1);   // get the char you are going to delete
var selection  = selection.text;    // there got the deleted stuff
var whereat = document.selection.createRange().duplicate();
whereat .moveStart("character",-1);   // move to where this would go back
whereat .moveEnd("character",-1);   // start and end now both at position
whereat .moveStart("textedit",-1);   // move start to begining of textarea (sometimes this goes to begin of doc)
var whereat = whereat.text.length;

it will take lots of testing and be browser dependant, lots of weird things like to happen with the selections too, like textedit-1 takes you to the begining of the document so you need to embed a hidden span with funny chars so you can split the string to find the real value and such

oh, another sneekie way you could to it is
onbeforecut  get selection
onkeydown  get the char to the left of selection

then

insert some unique chars, split the whole textarea by the chars, count the chars in the first arry of the split, then remove chars :)

-w


0
 

Author Comment

by:msalamon
ID: 9791064
Using a combination of the ideas you gave me and some ideas I read elsewhere to figure out the index position of the cursor in a textarea, I managed to succeed about 85%.  The code below mostly works (although in some cases I don't know why it works), but it does NOT work appropriately when you try to delete (with the "delete" key) a single character.  It works fine for these situations where you try to delete text:  backspace a single character or backspace/delete/ctrl-x/right-mouse-cut selected text.  I trying playing around wth lots of combinations of changes, but none of them worked.  (btw, I noticed that mozilla has a built in undo feature, but not IE.)

The code below basically takes the selected text, replaces it with a ~ (which should not be in the text in the first place), gets all of the text in the textarea (which now has the ~), finds the index of the ~, then reverts the text back the way it was, allowing any of the delete types to go forward.  What appears to happen with the "delete" key where you are deleting a single character is that moveEnd() position of the textrange is incremented by 1 (to capture the character to be deleted, for undo purposes), the char to be deleted gets replaced by ~ (and is never changed back), and then the delete goes forward to the character to the right of the one you wanted deleted.  For example, if you had:
     ABC
and tried to delete the A, you would end up with:
     ~C
where the A was replaced by the ~ and the B deleted.  I put a comment in that shows a line of code that will not delete the B, but still leaves the ~ in place.

Here is the relevant code.

<script language="javascript">
var versions = new Array();
function disableNonDelete()
{
      var e = event;
      if(e.keyCode == 8 || e.keyCode == 46 || (e.keyCode == 88 && e.ctrlKey))
      {
            var undoObject = new Object();
            undoObject.text = "";
            undoObject.start = 0;
            var tr = document.selection.createRange();
            var trCopy = document.selection.createRange().duplicate();

            if(tr.text == "")
            {
                  if(e.keyCode == 8)
                  {
                        tr.moveStart("character",-1);
                        if(tr.text == "")
                              return true;
                        undoObject.text = tr.text;
                  }
                  else if(e.keyCode == 46)
                  {
                        tr.moveEnd("character",1);
                        if(tr.text == "")
                              return true;
                        undoObject.text = tr.text;
//tr.moveEnd("character",-1);
                  }
                        else
                              return false;
            }
            else
                  undoObject.text = tr.text;

            tr.text = "~";
            undoObject.start = document.mda.delete_only.value.indexOf("~");
            versions[versions.length]=undoObject;
            tr = trCopy;
            document.mda.undo_button.disabled=false;
            return true;
      }
      else if (e.keyCode >= 37 && e.keyCode <=40)
            return true;
      else
            return false;
}

// the function for handling the right mouse click-cut is similar to above and works fine

function undo()
{
      if(versions.length > 0)
      {
            var undoObject = versions[versions.length-1];
            versions.length=versions.length-1;

            var text = document.mda.delete_only.value;
            var before = text.substring(0,undoObject.start);
            var after = text.substring(undoObject.start, text.length);
            document.mda.delete_only.value = before + undoObject.text + after;
      }
}

</script>

<form name="mda">
<textarea name="delete_only" cols="50" rows="10" wrap="soft"
onKeyDown="return disableNonDelete();"
onbeforepaste="event.returnValue=false"
onpaste="event.returnValue=false"
oncut="return onCut();"
>
WHATEVER TEXT YOU WANT HERE
</textarea>

<p>
<button name="undo_button" onclick="if(versions.length > 0) {undo(); if(versions.length == 0) {this.disabled=true;}}" disabled>Undo Last Change</button>

...
</form>

0
 
LVL 16

Expert Comment

by:jaysolomon
ID: 10382958
No comment has been added lately, so it's time to clean up this TA.
I will leave the following recommendation for this question in the Cleanup topic area:

PAQ with points refunded

Please leave any comments here within the next four days.
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

jAy
EE Cleanup Volunteer
0
 

Accepted Solution

by:
SpazMODic earned 0 total points
ID: 10420404
PAQed, with points refunded (250)

SpazMODic
EE Moderator
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Suggested Solutions

In this article, we'll look how to sort an Array in JavaScript, including the more advanced techniques of sorting a collection of records either ascending or descending on two or more fields. Basic Sorting of Arrays First, let's look at the …
Having worked on larger scale sites, we found out that you are bound to look at more scalable solutions to integrating widgets, code snippets or complete applications and mesh them into functional sites, in any given composition. To share some of…
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now