Edit HTML forms in external editor


Installation:
    - Copy both scripts to your scriptd_dir.
    - Add the following to config:
          @bind E = spawn @scripts_dir/external_editor.sh
    - chmod +x external_editor.sh
    - Set your preferred editor in external_editor.sh:
          edit_cmd = gvim
          edit_cmd = xterm -e vim
    - Set scripts_dir in external_editor.sh

Usage:
    - Select (click/use the linkfollower) an editable form, go to command mode and hit E

Bugs:
    I am not sure, maybe it fails sometimes (he, how accurate)
    It should be able to handle every char (tested the common german ones (öäüÖÄÜß).
    But with some char combination it fails I think. Don't know why.

external_editor.sh:

#!/bin/bash
 
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the -Do What The Fuck You Want
# To Public License-, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
 
# probably change it
scripts_dir="$XDG_DATA_HOME/uzbl/scripts"
edit_cmd="xterm -e $EDITOR"
 
element=`echo 'js document.activeElement.type' | socat -t 0 - unix-connect:$5 | grep -v EVENT`
value=`echo 'js document.activeElement.value' | socat -t 0 - unix-connect:$5 | grep -v EVENT`
 
#if [ "$element" = 'textarea' ]
if [ "$element" = 'text' -o "$element" = 'textarea' ]
then
    tmp_file=`mktemp /tmp/uzbl_edit.XXXXX`
    echo -n "$value" > $tmp_file
    $edit_cmd $tmp_file
    if [ "$value" != "$(< $tmp_file)" ]
        then
        echo "script $scripts_dir/base64.js" >> $4
        # in case that actelem.type has changed, we do this test
        echo "js var actelem = document.activeElement; if(actelem.type == 'text' || actelem.type == 'textarea') {actelem.value = decode64('`base64 $tmp_file`')};" | socat - unix-connect:$5 > /dev/null
    fi
    rm -rf $tmp_file
fi

base64.js:

/* 
 * utf8 function is (c) by Webtoolkit.info (http://www.webtoolkit.info/javascript-base64.html)
 * base64 function is (c) by Ntt.CC (http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html)
 * (both slightly modified)
 *
*/ 
 
 
var keyStr = "ABCDEFGHIJKLMNOP" +
             "QRSTUVWXYZabcdef" +
             "ghijklmnopqrstuv" +
             "wxyz0123456789+/" +
             "="
 
function decode64(input) {
    var output = "";
    var chr1, chr2, chr3 = "";
    var enc1, enc2, enc3, enc4 = "";
    var i = 0;
 
    // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
    var base64test = /[^A-Za-z0-9\+\/\=]/g;
    if (base64test.exec(input)) {
        return "Oh crap!";
    }
    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
 
    do {
        enc1 = keyStr.indexOf(input.charAt(i++));
        enc2 = keyStr.indexOf(input.charAt(i++));
        enc3 = keyStr.indexOf(input.charAt(i++));
        enc4 = keyStr.indexOf(input.charAt(i++));
 
        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;
 
        output = output + String.fromCharCode(chr1);
 
        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }
 
        chr1 = chr2 = chr3 = "";
        enc1 = enc2 = enc3 = enc4 = "";
 
    } while (i < input.length);
 
    return unescape(utf_decode(output));
}
 
function utf_decode(utftext) {
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;
 
    while ( i < utftext.length ) {
        c = utftext.charCodeAt(i);
        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        }
        else if((c > 191) && (c < 224)) {
            c2 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
            i += 2;
        }
        else {
            c2 = utftext.charCodeAt(i+1);
            c3 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }
    }
    return string;
}

The old, broken version

 
/* 
 * Edit forms in external editor
 *
 * (c) 2009, Robert Manea
 * utf8 functions are (c) by Webtoolkit.info (http://www.webtoolkit.info/)
 *
 *
 * Installation:
 *      - Copy this script to $HOME/.local/share/uzbl/scripts
 *      - Add the following to $HOME/.config/uzbl/config:
 *          @bind E = script @scripts_dir/extedit.js
 *      - Set your preferred editor
 *          set editor = gvim
 *      - non-GUI editors
 *          set editor = xterm -e vim
 *
 * Usage:
 *      Select (click) an editable form, go to command mode and hit E
 *
*/ 
 
 
function utf8_decode ( str_data ) {
    var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0;
    
    str_data += '';
    
    while ( i < str_data.length ) {
        c1 = str_data.charCodeAt(i);
        if (c1 < 128) {
            tmp_arr[ac++] = String.fromCharCode(c1);
            i++;
        } else if ((c1 > 191) && (c1 < 224)) {
            c2 = str_data.charCodeAt(i+1);
            tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
            i += 2;
        } else {
            c2 = str_data.charCodeAt(i+1);
            c3 = str_data.charCodeAt(i+2);
            tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }
    }
 
    return tmp_arr.join('');
}
 
 
function utf8_encode ( argString ) {
    var string = (argString+''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n");
 
    var utftext = "";
    var start, end;
    var stringl = 0;
 
    start = end = 0;
    stringl = string.length;
    for (var n = 0; n < stringl; n++) {
        var c1 = string.charCodeAt(n);
        var enc = null;
 
        if (c1 < 128) {
            end++;
        } else if (c1 > 127 && c1 < 2048) {
            enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128);
        } else {
            enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128);
        }
        if (enc !== null) {
            if (end > start) {
                utftext += string.substring(start, end);
            }
            utftext += enc;
            start = end = n+1;
        }
    }
 
    if (end > start) {
        utftext += string.substring(start, string.length);
    }
 
    return utftext;
}
 
 
(function() {
 var actelem  = document.activeElement;
 
 if(actelem.type == 'text' || actelem.type == 'textarea') {
    var editor   = Uzbl.run("print @external_editor") || "gvim";
    var filename = Uzbl.run("print @(mktemp /tmp/uzbl_edit.XXXXXX)@");
 
    if(actelem.value)
        Uzbl.run("sh 'echo " + window.btoa(utf8_encode(actelem.value)) + " | base64 -d > " + filename + "'");
 
    Uzbl.run("sync_sh '" + editor + " " + filename + "'");
    actelem.value = utf8_decode(window.atob(Uzbl.run("print @(base64 -w 0 " + filename + ")@")));
 
    Uzbl.run("sh 'rm -f " + filename + "'");
 }
 
 })();

I think this excellent script, which I am using to make this very edit, has a small bug which adds an extra space to whatever I type.

Fixed it by changing the return of utf8_decode to: <code javascript>

  return tmp_arr.join('').slice(0, -1);

<code>