How to remove a text field on a CGI perl webpage? - perl

I am rewriting this question to make it specific:
The requirement of the webpage is
Read the rules from a file and populate the text-boxes when the webpage is loaded
An add button to add additional textboxes
A save button to save the rules ( including the additionally added ones back to the file)
A delete button to delete the textboxes which are checked so that the rules in them are not stored back to the file.
My approach :
Use "read_rules" submodule to read the rules from the webpage and if its non empty then use "rule" submodule to print them on webpage. Here each line in the file is read and split with spaces and put in a array of hash and prints on the webpage ("rules" module).
When the sumit button is pressed sumodule "save_rules" is called which saves the rules. The reverse way as in read_rules.
An add button will add additional text areas.
A delete button should delete the text areas which are checked and reload the page so when the page is reloaded the text areas which were checked wont appear and hence when save button is pressed they are not saved in file ??? (this I have to implement)
The code blocks of each submodule I have mentioned are below.
This submodule to print the text boxes and checkbox:
sub rule {
my($num,$rule) = #_;
return join "\n",
"<tr><td><br>",
hidden(
-name => "idx$num",
-default => $rule->{idx},
),
checkbox(
-name => "checkbox$num",
-label => "",
-value => "on",
),
"<td>",
textfield(
-name => "repository$num",
-size => 30,
-default => $rule->{'repo'},
),
"<td>",
textfield(
-name => "branch$num",
-size => 30,
-default => $rule->{'branch'},
),
"<td>",
textfield(
-name => "file$num",
-size => 30,
-default => $rule->{'file'},
),
}
This sumodule to read the rules from file
sub read_rules {
my $rule;
#rules = ..# read the rules from a file, each line is read as an element of an array
for $rule (#rules){
my $rec = {};
($re,$br,$fi) = split (' ', $rule);
$rec->{'repo'} = $re;
$rec->{'branch'} = $br;
$rec->{'file'} = $fi;
push #config, $rec;
}
}
The sumodule to save the rule on webpage ( in text area) back to the file
sub save_rules {
for ($i = 1; param("repository$i"); $i++) {
$repo1 = param("repository$i");
$branch1 = param("branch$i");
$file1 = param("file$i");
my $record = {};
# save back $myrec->{'repo1'} $myrec->{'branch1'} $myrec->{'file1'} to file
}
}
Main function
print start_form();
read_rules();
Delete_all();
my $i = 0;
if (#config) {
foreach $conf (#config) {
$i++;
print rule($i,$conf);
}
print $table_header_string;
if (param("action") eq "Add") {
print(br,rule(++$i),hr);
}
print p( submit (-name => "action" , -value => "Add"));
print p( submit (-name => "action" , -value => "Save"));
print p( submit (-name => "action" , -value => "Delete"));
print end_form();
exit 0;
Delete_rule submodule below has to be coded !!
sub delete_rule(){
#................
}
I would appreciate if some one tells me how to use javascript in cgi so I don't have to load webpage every time a button is pressed.

Edited to address more specific question
Given that you don't want to reload the page each time the button is clicked, you are going to want to use JavaScript to do this. I'll explain how here, and you can click here to see a working jsfiddle example.
<!doctype html>
<html>
<head>
<title>Remove Element On Button Click</title>
</head>
<body>
<input type="text" id="myTextBox" value="something here">
<input type="button" id="btnDelete">
</body>
<script>
document.getElementById('btnDelete').onclick = function ()
{
var textbox = document.getElementById('myTextBox');
textbox.parentNode.removeChild(textbox);
}
</script>
</html>
Notice that I changed the type of input element from submit to button. This automatically prevents the page from reloading.
If you absolutely must use a submit input element (and the jsFiddle example does), you can prevent form submission by changing the Javascript thusly:
document.getElementById('btnDelete').onclick = function (evt)
{
if (!evt) var evt = window.event;
if (evt.preventDefault) { evt.preventDefault(); } else { evt.returnValue = false; }
var textbox = document.getElementById('myTextBox');
textbox.parentNode.removeChild(textbox);
}
The JavaScript can be placed in an external file, if prefered. It's placed at the end of the HTML here so as to ensure that the DOM had fully loaded (and hence the button was available in the DOM) prior to attempting to attach an event handler.
It was unclear to me whether there would be one or multiple 'Delete' buttons in your output, or if there would be one or multiple fields that would need to be removed, but this should point you in the right direction.
This is a pure JavaScript solution. As #vol7ron correctly pointed out, there are JavaScript frameworks, like jQuery, that could be used to do this as well, and if you are already using such a framework it would be advantageous to utilize it, however no such framework is in anyway required to accomplish this.

Related

TYPO3: How to render translated content in extension

I am developing a TYPO3 6.0 plugin that shows the subpages of the current page as tabs. For example, on the following pages my plugin is inserted on TabRoot:
If TabRoot is requested, the plugin's ActionController looks up the database for the subpage titles and contents and passes all gathered data to a Fluid template. The page is then rendered like the following:
With JS in place I always hide/show content below based on the selection. My problem is that I want to show the translated content of the subpages based on the current language selection. How am I able to do this? I've tried it with several methods, but neither of them was flawless. These are the methods I've tried:
Using RECORDS This method is not affected by the selected language, it always returns the content in the default language:
//Get the ids of the parts of the page
$select_fields = "uid";
$from_table = "tt_content";
$where_clause = 'pid = ' . $pageId;
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
$select_fields,
$from_table,
$where_clause,
$groupBy='',
$orderBy='sorting',
$limit=''
);
$ids = '';
$firstIteration = true;
while ( $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc( $res ) ) {
if (!$firstIteration) $ids .= ",";
$ids .= $row ['uid'];
$firstIteration = false;
}
$GLOBALS['TYPO3_DB']->sql_free_result( $res );
//Render the parts of the page
$conf ['tables'] = 'tt_content';
$conf ['source'] = $ids;
$conf ['dontCheckPid'] = 1;
$content = $this->cObj->cObjGetSingle ( 'RECORDS', $conf );
Using CONTENTS According to TYPO3: How to render localized tt_content in own extension, this is the way to do it, however for me this also returns the content rendered with the default language. It is not affected by a language change.
$conf = array(
'table' => 'tt_content',
'select.' => array(
'pidInList' => $pageId,
'orderBy' => 'sorting',
'languageField' => 'sys_language_uid'
)
);
$content = $this->cObj->cObjGetSingle ( 'CONTENT', $conf );
Using VHS: Fluid ViewHelpers I installed the vhs extension and tried to render the content with <v:content.render />. The result is the same as with CONTENTS; it only works with the default language.
{namespace v=Tx_Vhs_ViewHelpers}
...
<v:content.render column="0" order="'sorting'" sortDirection="'ASC'"
pageUid="{pageId}" render="1" hideUntranslated="1" />
Using my own SQL query I've tried to get the bodytext fields of the page and then render those with \TYPO3\CMS\Frontend\Plugin\AbstractPlugin::pi_RTEcssText(). This method returns the content based on the current language, however the problem is that bodytext's do not contain the complete content (images, other plugins, etc).
$select_fields = "bodytext";
$from_table = "tt_content";
$where_clause = 'pid = ' . $pageId
. ' AND sys_language_uid = ' . $GLOBALS ['TSFE']->sys_language_uid;
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
$select_fields,
$from_table,
$where_clause,
$groupBy='',
$orderBy='sorting',
$limit=''
);
$content = '';
while ( $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc( $res ) ) {
$content .=
\TYPO3\CMS\Frontend\Plugin\AbstractPlugin::pi_RTEcssText( $row ['bodytext'] );
}
$GLOBALS['TYPO3_DB']->sql_free_result( $res );
What am I missing? Why isn't the content rendered with the current language in the case of the CONTENTS method?
Easiest way is to use the cObject viewhelper to render right from TypoScript.
And inside your TypoScript template provide the configuration:
lib.myContent = CONTENT
lib.myContent {
...
}
BTW, you are bypassing the TYPO3 CMS API. Please do not do so. Always use the API methods to query for data.
e.g. \TYPO3\CMS\core\Database\DatabaseConnection is always available at GLOBALS['TYPO3_DB']->. Do not use the the mysql function.
On top of that, I believe that you can archive whatever you are trying to do with pure TypoScript, without the need to program anything. Feel free to ask a new questions to get help on this.
In TYPO3 4.x you could use the following methods to load the translated record:
t3lib_pageSelect->getRecordOverlay
t3lib_pageSelect->getPageOverlay
They are also available at $GLOBALS['TSFE']->sys_page->getRecordOverlay().

How to assign Action to a Button in perl cgi?

So I have a button in my CGI Perl. On clicking that button I need to assign a action in perl CGI, on clicking that button a New text-area should open with specified width in the same page with a submit button. Please help me on how I can proceed. Here is the code which is not really working for me. On clicking on submit button, I what to email the message to a email id
Here I print the button
print button('email',"email me","reqts()");
Here is the opentextarea subroutine
sub reqts {
print "<p><em>Enter your Message here</em><br>";
print textarea(-name=>'Comments',
-rows=>10,
-columns=>50);
print submit('Action','Send');
}
On clicking this button the subroutine is not getting called.
This button is on a html form in another subroutine
sub actions {
print
start_html(),
start_form(-action => 'com.pl'),
submit(-name => 'submit', -value => 'View com.pl'),
end_form,
print button('email',"email me","reqts()"), # this is the button
start_form(-action => 'about.pl'),
submit(-name => 'submit', -value => 'About Us');
end_form,
end_html;
}
The onClick attribute (the third argument to button) should be a JavaScript function, not Perl function. You should study how CGI and webpages work.

Formmail - make it show name and email in success response

I'm using formmail.pl to handle a form I'm using on my site. There are several fields which are sent to the script including name, email, phone and some text in a text area.
As it stands, the successful submission prints the phone and textarea data correctly but doesn't print the name and email which were entered. In the email it sends the name and email in the 'from' header and as with the success page only shows the phone and textarea data are shown in the email body.
I would like to show all data in both cases however I can't seem to find the section of code that handles this. I'd post up the formmail.pl script except its over 3000 lines of code so I'll just post the places I think are responsible and hopefully somebody can point me in the right direction. I'm fairly new to Perl and its a bit overwhelming reading and understanding a script of this size.
sub success_page {
my ($self, $date) = #_;
if ($self->{FormConfig}{'redirect'}) {
print $self->cgi_object->redirect( $self->{FormConfig}{'redirect'} );
}
elsif ( $self->{CFG}{'no_content'}) {
print $self->cgi_object->header(Status => 204);
}
else {
$self->output_cgi_html_header;
$self->success_page_html_preamble($date);
$self->success_page_fields;
$self->success_page_footer;
}
}
sub success_page_html_preamble {
my ($self, $date) = #_;
my $title = $self->escape_html( $self->{FormConfig}{'title'} || 'Success' );
my $torecipient = 'to ' . $self->escape_html($self->{FormConfig}{'recipient'});
$torecipient = '' if $self->{Hide_Recipient};
my $attr = $self->body_attributes;
print <<END;
<head>
<title>$title</title>
END
$self->output_style_element;
print <<END;
<link type="text/css" href="css/stylesheet.css" rel="stylesheet" /></script>
</head>
<body>
<p>Below is what you submitted $torecipient on $date</p>
END
}
sub success_page_fields {
my ($self) = #_;
foreach my $f (#{ $self->{Field_Order} }) {
my $val = (defined $self->{Form}{$f} ? $self->{Form}{$f} : '');
$self->success_page_field( $self->escape_html($f), $self->escape_html($val) );
}
}
sub success_page_field {
my ($self, $name, $value) = #_;
print "<p><b>$name:</b> $value</p>\n";
}
Okay that's getting a bit long. That stuff is mostly for the success page and not much to do with the email side of things but maybe if somebody can find what I need there I can apply it to the email section also.
If any further information is needed let me know
Thanks in Advance
I haven't really used NMS FormMail myself, but looking at the source, it seems that you should be able to achieve something like what you want by setting the following extra configuration options:
$more_config{include_config_email} = 1;
$more_config{include_config_realname} = 1;
This should cause FormMail.pl to treat the email and realname fields as normal form fields, in addition to their special meaning.

How Upload file using Mojolicious?

I have been trying out Mojolicious web framework based on perl. And I have try to develop a full application instead of the Lite. The problem I am facing is that I am trying to upload files to server, but the below code is not working.
Please guide me what is wrong with it. Also, if the file gets uploaded then is it in public folder of the application or some place else.
Thanks in advance.
sub posted {
my $self = shift;
my $logger = $self->app->log;
my $filetype = $self->req->param('filetype');
my $fileuploaded = $self->req->upload('upload');
$logger->debug("filetype: $filetype");
$logger->debug("upload: $fileuploaded");
return $self->render(message => 'File is not available.')
unless ($fileuploaded);
return $self->render(message => 'File is too big.', status => 200)
if $self->req->is_limit_exceeded;
# Render template "example/posted.html.ep" with message
$self->render(message => 'Stuff Uploaded in this website.');
}
(First, you need some HTML form with method="post" and enctype="multipart/form-data", and a input type="file" with name="upload". Just to be sure.)
If there were no errors, $fileuploaded would be a Mojo::Upload. Then you could check its size, its headers, you could slurp it or move it, with $fileuploaded->move_to('path/file.ext').
Taken from a strange example.
To process uploading files you should use $c->req->uploads
post '/' => sub {
my $c = shift;
my #files;
for my $file (#{$c->req->uploads('files')}) {
my $size = $file->size;
my $name = $file->filename;
push #files, "$name ($size)";
$file->move_to("C:\\Program Files\\Apache Software Foundation\\Apache24\\htdocs\\ProcessingFolder\\".$name);
}
$c->render(text => "#files");
} => 'save';
See full code here: https://stackoverflow.com/a/28605563/4632019
You can use Mojolicious::Plugin::RenderFile
Mojolicious::Plugin::RenderFile

How can i repeatedly prompt the user with Tkx?

Using Perl Tkx, I want to get some input from the user, close the window, and maybe do it again later. For user input, I'm just displaying some buttons, and the user gets to click on one of them. Here's what I have now:
sub prompt_user {
my $answer;
my $mw = Tkx::widget->new("."); ## the main window is unavailable the second time
$mw->g_wm_title("Window Title"); ## line 40
$mw->g_wm_minsize(300, 200);
my $label = $mw->new_label( -text => "Question to the user?");
$label->g_pack( -padx => 10, -pady => 10);
my $button1 = $mw->new_button(
-text => "Option One",
-command => sub { $answer = 0; $mw->g_destroy; },
);
$button1->g_pack( -padx => 10, -pady => 10);
my $button2 = $mw->new_button(
-text => "Option Two",
-command => sub { $answer = 1; $mw->g_destroy; },
);
$button2->g_pack( -padx => 10, -pady => 10);
Tkx::MainLoop(); ## This blocks until the main window is killed
return $answer;
}
So the user clicks on one of the buttons, the window closes, prompt_user() returns 0 or 1 (depending on which button the user clicked), and execution continues. Until I try to prompt the user again. Then I get an error:
can't invoke "wm" command: application has been destroyed at MyFile.pm line 40
I just want a way to put up a bunch of buttons, let the user click one, wait to see which one is clicked, and maybe do it again later. Is there a way I can wait for a response to the button click without destroying the main window? Maybe create a subwindow?
I'm new to using Tkx, and googling shows lots of simple examples like the above code (using MainLoop/g_destroy), but I couldn't find any examples of recreating windows. I did see stuff about a Dialog Box or Message Box, but those won't suit my needs. I want to put text on the buttons, and use an arbitrary number of buttons (so I don't want to be limited to yes/no/cancel, and only have 3 options).
Update
Here's what I was able to use
# hide the main window, since I'm not using it
my $mw = Tkx::widget->new(".");
$mw->g_wm_withdraw();
# function to prompt the user to answer a question
# displays an arbitrary number of answers, each on its own button
sub prompt {
my $prompt = shift;
my $list_of_answers = shift;
# Note: the window name doesn't matter, as long as it's './something'
my $answer = Tkx::tk___dialog( "./mywindowpath", # window name
"Prompt", # window title
$prompt, # text to display
undef, # tk bmp library icon
undef, # default button
#$list_of_answers); # list of strings to use as buttons
return $answer;
}
# use the button to ask a question
my $index = prompt("Who was the best captain?",
[ "Kirk", "Picard", "Cisco", "Janeway", "Archer" ] );
I'm not really familiar with Tkx but Tk doesn't really work well that way. In general Tk applications are asynchronous. You should re-write your application in term of callbacks (kind of like javascript).
Basically, this kind of logic:
sub do_something {
perform_some_action();
my $result = prompt_user();
perform_some_other_action($result);
}
should be re-written to something like:
sub do_something {
perform_some_action();
prompt_user(perform_some_other_action);
}
Your program should basically not have a main loop. Instead the call to Tkx::MainLoop at the end of your program becomes the main loop and you should do all processing by handling events.
Having said that, there are some mechanisms available that emulates blocking. Read the documantation for vwait. Though, I think even that requires a running Tkx::MainLoop so it does not necessarily avoid refactoring your whole program.
On the question of how to create and destroy windows there are two solutions:
Use the main window (.) but don't destroy it at the end. Instead hide it and destroy all its children. You can then later reuse . by unhiding it.
Hide . and don't use it. Instead create other windows (toplevels) and use them. Since toplevels are children of . they are safe to destroy without screwing up Tk.