File: spel
# All Lines | # Code Lines | View the Viewer
#!/usr/bin/perl
use warnings;
use strict;
use Text::Aspell;
use CGI qw(:standard);
$CGI::POST_MAX = 2_000;  # play nice now
#=====================================================================
print
    header,
    start_html(-title => 'Bad speling is bad'),
    script({-type => 'text/javascript',},
           <<'SCRIPThere'
function changeText(elmid, badword, goodword, optionid) {
   textBlock = document.getElementById(elmid);
   regex = new RegExp('\\b' + badword + '\\b', 'g');
   textBlock.value = textBlock.value.replace(regex,goodword);
   option = document.getElementById(optionid);
   option.style.display = 'none';
}
SCRIPThere
           ),
    start_form(),    
    div({ -style => "position:absolute;top:25px;left:25px;"},
        b("Enter text to spellcheck"),
        br,
        textarea(
                 -class => 'textbox',
                 -name => 'text1',
                 -id => 'text1',
                 -style => "width:250px;height:5em",
                 -wrap => 'virtual',
                 -rows => 9),
        ),
    div({-style => "position:absolute;top:55px;left:275px;"},
        submit(-name => 'speling?',
               -style => 'z-index:99;'),
        ),
    div({-style => "position:absolute;top:25px;" .
           "left:360px;font-size:80%"},
        do_spelling_feedback( 'text1', param('text1') )
        ),
    end_form,
    end_html;

exit 0;
#=====================================================================
# SUBROUTINES
#=====================================================================
sub do_spelling_feedback {
    my ( $field, $text ) = @_;

    warn "Field name missing in call to do_spelling_feedback()"
        unless $field;
    return '' unless $text;

    my $speller = get_speller();
    my ( @badwords, %seen, $tail );
    $tail = 'a';
    while ( $text =~ /(['\w]+)/g ) { # add apos back
        my $word = $1;
        next if $seen{$word}++;
        unless ( $speller->check( $word ) ) {
            my @sug = $speller->suggest( $word ); 
            # Five is plenty
            @sug = splice(@sug,0,6) if @sug > 6;

            my $rando_id = 'id_' . $tail++;
            my @link = 
                map {
                    a({-href=>'javascript:void()',
                       -onclick =>
                           join('',
                                "changeText('$field','",
                                quotemeta($word),
                                "','",
                                quotemeta($_),
                                "','$rando_id'",
                                ")"
                                )
                       },
                      $_
                      ) } @sug;

            push @badwords, 
                div({-style=>"display:block",
                     -id => $rando_id },
                    b({-style => 'background-color:#ff9;'.
                         'padding:0px 3px 0px 3px;'},
                      $word, ),
                    div({-style => 'padding:0px 0px 4px 12px;'},
                        @link ? 
                        join(', ', @link) :
                        "Sorry, no suggestion"
                        )
                    );
        }
    }

    return
        div(
            b("Click a word to make a correction",),
            br,
            join("\n", @badwords)
            ) 
        if @badwords;

    return
    'Everything looks okay. Try to misspell something.<br />' .
    a({-href=>'./spel.cgi?text1=Foor+ezampel,+yoo+culd+yuse+thise.'},
    'Foor ezampel, yoo culd yuse thise.');
}
#=====================================================================
sub get_speller {
    my $speller = Text::Aspell->new;
    die unless $speller;

    $speller->set_option('lang','en_US');
    $speller->set_option('sug-mode','fast');

# the home-dir must exist & be read/write by the webserver user
    $speller->set_option('home-dir', '/www');

    return $speller;
}
#=====================================================================
sub add_to_dictionary {

    die "Not implemented -- " .
        "feel free to finish it out in your own app.";

    my $word = param('word');

    print h2("Adding $word to dictionary");

    my $speller = get_speller();

    print $speller->add_to_personal($word) ?
        h3("success!") : h3("failed!");

    $speller->save_all_word_lists;
}
#=====================================================================