Many web sites, E2 included, rely on forms for the entry of large volumes of text. The most widely used and convenient method for doing this is to use HTML's textarea construct (alternatives being to use file upload of text edited elsewhere; or alternatively multiple 'text' input fields), which gives the user an area into which text may be typed.

This is all very well and good in theory; however, in practice no web browser I've ever used provides a rich enough set of features to make editing text, let alone HTML, in a textarea a viable proposition for anything more than trivial changes. In one ideal for the 'perfect browser', the functions of editting text in a textarea would be delegated via library calls to a standard, powerful text editor, and all would be good. However, currrent browsers are lacking in even such basic features as text replace.

Fortunately, these same browsers tend to come equipped with ECMAscript, or JavaScript. Many missing features can be implemented using code embedded in web pages, or using bookmarklets. To wit, here's a short collection of bookmarklets that implement a few useful functions: regular expression replacement, basic text to HTML conversion, and an HTML preview (these last two since it's so often HTML that's edited in textareas), with an undo function as well...

Replace...
javascript: var f, i, form; var a, b, n; n=0; a=prompt('Replace regexp...'); if (a != null) b=prompt('...with', a); if (a != null && b != null) { for (f=0; f<document.forms.length; f++) { form=document.forms[f]; for (i=0; i<form.length; i++) { if (form[i].type == 'textarea') { n++; form[i].undo = form[i].value; form[i].value = form[i].value.replace(new RegExp(a, 'g'), b); }; }; }; window.status='Replaced in '+n+' textareas'; }; document.url = document.url;
Format
javascript: var f, i, form; n=0; for (f=0; f<document.forms.length; f++) { form=document.forms[f]; for (i=0; i<form.length; i++) { if (form[i].type == 'textarea') { n++; form[i].undo = form[i].value; form[i].value = form[i].value.replace(new RegExp('(<br>)|(</?p>)', 'g'), ''); form[i].value = form[i].value.replace(new RegExp('(\n|\r)', 'g'), '<br>$1'); form[i].value = '<p>'+form[i].value.replace(new RegExp('<br>(\n|\r)<br>((\n|\r)<br>)*', 'g'), '$1</p>$1$1<p>')+'</p>'; }; }; }; window.status='Formatted in '+n+' textareas'; document.url = document.url;
Undo
javascript: var f, i, form; n=0; for (f=0; f<document.forms.length; f++) { form=document.forms[f]; for (i=0; i<form.length; i++) { if (form[i].type == 'textarea') { n++; if (form[i].undo != null) { form[i].value = form[i].undo; }; }; }; }; window.status=''+n+' textareas restored'; document.url = document.url;
Preview...
javascript: var f, i, form, w; n=0; for (f=0; f<document.forms.length; f++) { form=document.forms[f]; for (i=0; i<form.length; i++) { if (form[i].type == 'textarea') { var t = form[i] .value; n++; w=window.open(); w.document.write('<html>', t, '</html>'); }; }; }; document.url = document.url;

The 'bookmarklet' writeup explains what they are, and how to use these with your browser; in short, there are two options:

  1. Copy the code from this writeup, create a new bookmark or 'favourites' item, and paste the text in there.
  2. Visit http://kahani.org/e2/bookmarklets.html and drag the links to your Personal Toolbar or Favourites Toolbar.

Personally I much prefer option 2.

I have these bookmarklets within a 'TextArea' folder in my personal toolbar; the overal effect is much like that of having a proper 'edit' menu on my browser.

And, purely for academic interest, here's the perl code that outputs the bookmarklets in that nice, compact but impossible to write format that bookmarks have to be in.

#!/usr/bin/perl

sub bookmark {
  my ($code, $title) = @_;
  $code =~ s/\s+/ /g;	# Take out whitespace
  $code =~ s/"/\\"/g;	# take out quotes.
  return "<a href=\"$code\">$title</a>";
};

$replace=<<EOJS;

javascript:
var f, i, form;
var a, b, n;
n=0;
a=prompt('Replace regexp...');
if (a != null) 
  b=prompt('...with', a);
if (a != null && b != null) {
  for (f=0; f<document.forms.length; f++) {
    form=document.forms[f];
    for (i=0; i<form.length; i++) {
      if (form[i].type == 'textarea') {
        n++;
        form[i].undo = form[i].value;
        form[i].value = form[i].value.replace(new RegExp(a, 'g'), b);
      };
    };
  };
  window.status='Replaced in '+n+' textareas';
};
document.url = document.url;

EOJS


$undo=<<EOJS;

javascript:
var f, i, form;
n=0;
for (f=0; f<document.forms.length; f++) {
  form=document.forms[f];
  for (i=0; i<form.length; i++) {
    if (form[i].type == 'textarea') {
      n++;
      if (form[i].undo != null) {
        form[i].value = form[i].undo;
      };
    };
  };
};
window.status=''+n+' textareas restored';
document.url = document.url;

EOJS

$format=<<EOJS;

javascript:
var f, i, form;
n=0;
for (f=0; f<document.forms.length; f++) {
  form=document.forms[f];
  for (i=0; i<form.length; i++) {
    if (form[i].type == 'textarea') {
      n++;
      form[i].undo = form[i].value;
      form[i].value =
        form[i].value.replace(new RegExp('(<br>)|(</?p>)', 'g'), '');
      form[i].value = 
        form[i].value.replace(new RegExp('(\\n|\\r)', 'g'), '<br>\$1');
      form[i].value = 
        '<p>'+form[i].value.replace(new
        RegExp('<br>(\\n|\\r)<br>((\\n|\\r)<br>)*', 'g'),
        '\$1</p>\$1\$1<p>')+'</p>';
    };
  };
};
window.status='Formatted in '+n+' textareas';

document.url = document.url;

EOJS


# Preview HTML/writeup...
$preview=<<EOJS;

javascript:
var f, i, form, w;
n=0;
for (f=0; f<document.forms.length; f++) {
  form=document.forms[f];
  for (i=0; i<form.length; i++) {
    if (form[i].type == 'textarea') {
      var t = form[i].value;
      n++;
      w=window.open();
      w.document.write('<html>', t, '</html>');
    };
  };
};

document.url = document.url;

EOJS

print
  "<html>",
  bookmark($replace, "Replace..."), ' ',
  bookmark($format, "Format"), ' ',
  bookmark($undo, "Undo"), ' ',
  bookmark($preview, "Preview..."), ' ',
  "</html>\n";