#!/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/- /"\t".$i++."-"/e} @data;
map {s/<\/li>//} @data;
}elsif($line =~ s/<.?ul>//){
map {s/
- /"\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=" - Enter Item
\n";
$string = "\n".($listItems x $number)."\n
";
$pos = $textArea->index('insert');
$textArea->insert("$pos","$string");
}
sub Numbers{
my ($string, $pos);
$listItems="- Enter Item
\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.