#!/usr/local/bin/perl ########################################################################################################## ########################################################################################################## #This is a program that simulates some of the tasks of posting and previewing a node at PerlMonks. # # I thought of making such a program for the following reasons: # # 01-Practice the Tk module to a decent level or mastery. # # 02-Make a GUI that could enable Perl newbies to post nodes quicker without # # using some of the deprecated tags like
 and.                                                    #
#                    03-Participate at the Monastery by contributing something that can also be used     #
#   by everyone who wants a speedier approach to posting a node with some of the following advantages:   #
#                  *The lengthoverhead of the preview button response is minimized.                      #
#                  *Minimizing the clutter of the most used tags at your personalized node dispatcher.   #
#                  *Giving an insight into the MarkUp of the Monastery that is visualizable.             #
#                  *presenting wpl.exe to newbies and how it allows a program to run without console.    #
#                  *Some other advantages and ideas like checking the module availablity, strictures..etc#
#                   04- Improve my coding style and entertain constructive criticism from all.           #
##########################################################################################################
##########################################################################################################


                ###Checking whether the required modules are installed before everything else###

@modules=("use Tk", "require Tk::BrowseEntry", "require Tk::DialogBox","require Tk::Dialog");
foreach(@modules){
        eval;
        if($@){
                $_=~/\w+\W(\S+)/;
                print "Module $1 does not exist, please install it first!\n";
                }
        };
use strict;
use warnings;
use Tk;

                ## Declaring Main, side Panel, Top Panel, Text Area, preview Area and Two menus##
my ($main, $menuBar, $sideBar, $textBar,$textArea, $prevArea);
my ($fileMenu, $editMenu);
$main = MainWindow->new();
$main->title('PM HTML Encoder (BioHisham@gmail.com) ');
$menuBar=$main->Frame()->pack(-side=>'top',-fill=>'x');
$sideBar=$main->Frame()->pack(-side=>'left', -expand=>1, -fill=>'both');
$textBar=$main->Frame()->pack();
$fileMenu=$menuBar->Menubutton(-text=>'File', -relief=>'raised')->pack(-side=>'left');
$editMenu=$menuBar->Menubutton(-text=>'Edit', -relief=>'raised')->pack(-side=>'left');
$textArea=$textBar->Scrolled(           #text Area, the width is not the default 70 like the PM's,
                'Text',                 #because my screen width doesn't allow that.
                -scrollbars=>'ow',      #the o let's the scrollbar show when necessary.
                -width=>'50',
                -height=>'30'
                )->pack(-side=>'left');
$prevArea=$textBar->Scrolled(            #preview Area.
                'Text',
                -scrollbars=>'ow',
                -width=>'50',
                -height=>'30'
                )->pack(-side=>'right');



                      ## Populating the File menu and setting behavior ##
                   ## I dont know what else to place on these menus however :( ##

my $exitCmd=$fileMenu->command(
        -label=>'exit',
        -accelerator=>'(Alt + F4)',
        -command=>sub{exit;}
        );
$main->bind(''=>sub{exit;});

                     ########################################
                     ###     Buttons FOR:                 ###
                     ###    CODE, Paragraph,              ###
                     ###    preview, Read More,           ###
                     ###    Internal Links,               ###
                     ###    External Links,               ###
                     ###    Lists invocation and Preview  ###
                     ######################################

my ($codeTag, $html_var,$listTag,$readTag,$internLink, $extLink,$lineTag,$prevTag,$paraTag, $listButton, $resetAll);     #Buttons
$codeTag=$sideBar->Button(
        -text=>   'CODE',
        -relief=>'ridge',
        -height=> 2,
        -width=>  10,
        -command=>\&CodeIt)->pack();

$paraTag=$sideBar->Button(
        -text=>  'PARAGRAPH',
        -relief=>'ridge',
        -height=> 2,
        -width=>  10,
        -command=>\&ParaIt)->pack();


#$lineTag=$sideBar->Button(     #this is the 
not deployed yet # -text=>'Line Break', # -relief=>'ridge', # -height=> 2, # -width=>10, # -command=>\&LineIt # )->pack(); $readTag=$sideBar->Button( -text=> 'Read More', #Not sure I presented this the right way though cuz it confused me -relief=> 'ridge', -height=> 2, -width=> 10, -command=>\&LinkIt )->pack(); $internLink=$sideBar->Button( -text=> 'Internal link', -relief=> 'ridge', -height=> 2, -width=> 10, -command=>\&linkIt_Intern, )->pack(); $extLink=$sideBar->Button( -text=> 'External Link', -relief=> 'ridge', -height=> 2, -width=> 10, -command=> \&linkIt_Ext, )->pack(); $listButton=$sideBar->Button( #Hitting this button casuses many instances of the listBrowse widget -text=> 'list', -height=> 2, -width=> 10, -relief=> 'ridge', -command=> \&listBrowse, )->pack(); $resetAll=$sideBar->Button( -text=> 'Reset All', -height=> 3, -width=> 10, -relief=> 'groove', -background=>'white', -command=>sub{ for($textArea, $prevArea){ $_->delete('1.0','end'); } } )->pack(-fill=>'x', -expand=>'1', -side=>'bottom'); ## Since lists are either ordered or unordered I made a BrowseEntry ### ## to show lists types upon hitting the List Button. ### require Tk::BrowseEntry; require Tk::DialogBox; require Tk::Dialog; my $choice="number"; #the default list item. sub listBrowse{ $listTag=$sideBar->BrowseEntry( -variable=>\$choice, -browsecmd=>\&Verify )->pack(); $listTag->insert("end","Number"); $listTag->insert("end","Bullet"); } my ($number,$listItems, $dialog, $errorDialog, $entry); $dialog=$main->DialogBox( -title=>'Enter List Length', -buttons=>['ok', 'cancel'] ); $errorDialog=$main->Dialog( #this is an error message when the user enters -title=>'error', #an invalid choice in the DialogBox. -text=>'invalid number', -bitmap=>'error', -buttons=>['Ok'] ); $entry = $dialog->add( #adding an entry widget to the dialog box body. 'Entry', -width=>40, )->pack(); $prevTag=$sideBar->Button( -text=>'PREVIEW', -relief=>'ridge', -height=> 2, -width=>10, -command=> \&SeeIt, )->pack(); MainLoop; { #setting scope for $srting# sub CodeIt{ my ($string, $pos); $string = "\nPlace Code Here\n"; $textArea->insert('end',"$string"); } sub ParaIt{ my ($string, $pos); $string = "

\nenter some lines of text\n

"; $textArea->insert('end',"$string"); } sub SeeIt{ #this subroutine would create a temporary file to write the text area content to and then #would use the temporary file as the source to write to the preview area from. #N.B: I COULD NOT unlink OR delete THE TEMPORARY FILE THUS CREATED AND COULDN'T HANDLE THE while #LOOP TO WORK OFF THE TEXT AREA DIRECTLY WITHOUT CREATING AN INTERMEDIARY CHANNEL. my (@data, $line, $filename); $html_var=$textArea->get('1.0','end'); #get the text from the widget into a string variable. $filename="FileInputSample.tmp"; open FH, ">$filename" or die "$!"; print FH $html_var; open FH, "$filename", or die "$!"; while(@data=){ foreach $line (@data){ #This has been thorny because one list type overrules the other. #Could not get to allow mixing of list types. $line =~ s/(<.?code>)//; $line =~ s/(

|

    )/\n/; $line =~ s/<\/p>//; if($line =~ s/<.?ol>//){ my $i=1; map {s/
  1. /"\t".$i++."-"/e} @data; map {s/<\/li>//} @data; }elsif($line =~ s/<.?ul>//){ map {s/
  2. /"\t* "/e} @data; map {s/<\/li>//} @data; } #elsif } #foreach $prevArea->delete('1.0', 'end'); $prevArea->insert('1.0',"@data"); }#while close ('FH'); unlink("$filename") or die "Failed to delete the temporary file $!\n"; #deleting the file } #sub LineIt{ #related to the deactivate
    # $string="
    Enter a new Line"; # $pos=$textArea->index('insert'); #get current cursor position # $textArea->insert("$pos","$string"); # } sub LinkIt{ #When I tested this one, I don't think I can make it work as it should by #retracting the linked page to a mere hypertext. my ($string, $pos); $string=qq(" Text Goes here "); $pos=$textArea->index('insert'); $textArea->insert("$pos","$string"); } sub linkIt_Intern{ my ($string, $pos); $string = "[Node Name or Node ID, pad: or doc: or username]"; $pos = $textArea->index('insert'); $textArea->insert("$pos","$string"); } sub linkIt_Ext{ my ($string, $pos); $string = qq([href://http://www.Site.com|Label]); $pos=$textArea->index('insert'); $textArea->insert("$pos", "$string"); } my $result; #the result from the DialogBox which can be ok or cancel. my $flag; #a flag returned to control subroutines flow. sub Verify{ #whether the choice is equal to bulltes or numbers and act accordingly if($choice eq "Bullet"){ $entry->delete('0.0','end'); #reset the entry widget in the dialog box. my $result=$dialog->Show; #show the dialog box and capture response. if($result eq "ok"){ $number=$entry->get(); #if the return value of VerifyListNumber is 1 or 0 and acts accordingly: Bullets() if(VerifyListNumber()); #dont go to bullets() unless flag is 1 $errorDialog->Show() if(!VerifyListNumber()); #when the flag is 0. }elsif($result eq "cancel"){ $entry->delete('0.0','end'); return; } }elsif($choice eq "Number"){ $entry->delete('0.0','end'); my $result=$dialog->Show; if($result eq "ok"){ $number=$entry->get(); Numbers() if (VerifyListNumber()); $errorDialog->Show() if(!VerifyListNumber()); }elsif($result eq "cancel"){ $entry->delete('0.0','end'); return; } } } sub VerifyListNumber{ chomp $number; if($number=~/\D+/){ $flag=0; return $flag; }else{$flag=1; return $flag;} } sub Bullets{ my ($string, $pos); $listItems="
  3. Enter Item
  4. \n"; $string = "
      \n".($listItems x $number)."\n
    "; $pos = $textArea->index('insert'); $textArea->insert("$pos","$string"); } sub Numbers{ my ($string, $pos); $listItems="
  5. Enter Item
  6. \n"; $string = "
      \n".($listItems x $number)."\n
    "; $pos = $textArea->index('insert'); $textArea->insert("$pos","$string"); } }#ending the subroutines scope. # Any ideas, feedback and criticism are accepted with an open heart. # Thanks for your time, your efforts and your assitance. #This has been when I could come up with to the best of my abilities, I could not simulate underlined text to #represent links to websites, I couldn't get the program distinguish multiple instances of lists and operate #accordingly, there might be other bugs lurking around but I could not unearth them for a critical eye scanning #is sharper and finer than a learner's eye.