(Продолжение, начало см. МК № 46, 48, 50 (165, 167, 169))
Если вы до сих пор не понимаете, о чем идет речь — об HTML-странице или Perl-скрипте, поясню: и то, и другое находится в одном общем коде, благо синтаксис Perl’а позволяет вставлять в программу большие куски текста:
print<<END_TAG; текст....текст текст....текст текст....текст текст....текст END_TAG
В нашем случае все JS-функции и HTML-элемент div введены в perl-программу именно этим методом. Исполняемый Perl-код пишется после метки END_TAG. В целом структура скрипта выглядит так:
• Пишем заголовок скрипта;
• Объявляем соединения с mySQL-сервером;
• Оператором print<<TAG выводим заголовок HTML-кода;
• Perl’ом выводим список доступных категорий;
• Опять выводим оператором print<<NEXT_TAG остаток формы
• Пишем дальше на Perl’е обработку параметров;
• Если нужно сохранять — сохраняем (пишем соответствующую процедуру);
• Если нужно добавлять — добавляем (пишем соответствующую процедуру);
• Если нужно удалять — удаляем (пишем соответствующую процедуру);
Львиную долю работы по обслуживанию формы на клиентской машине, конечно, берет на себя JavaScript, — Perl только обрабатывает переданные формой аргументы и производит манипуляции с данными. Выигрыш в скорости обработки очевидна — за каждым кликом не нужно лезть на сервер.
Следующий шаг: вывести остаток формы и обработать входящие параметры.
print<<HTML_TOP; </select> <!-- закрываем SELECT --> </div> <!-- закрываем Layer со справочником --> <!-- И начинаем форму --> ... ... ... <!-- Окончание формы, описанной выше --> HTML_TOP
В общем, ничего сложного. Функции check_???() устанавливают значение скрытого поля edit. Далее — тривиальная проверка аргументов. От комментариев воздержусь.
&read_input; if ($data{'edit'} eq 'edit') { &save_values; print "<h3>Изменения сохранены!</h3>\n"; &show_page; } else { if ($data{'edit'} eq 'delete') { &delete_record; } else { &show_page; } }
Осталось написать четыре процедуры: &save_values, &show_page, &delete_record, &read_input. Последнюю здесь приводить не буду — чтение потока STDIN и заполнение хэша. Показ страницы производится при любом действии:
sub show_page { my $result = $dbh->prepare("SELECT a.name as cname, b.name as name, b.url as url, a.id as catid, b.id as lid FROM category a, links b WHERE b.category=a.id ORDER by a.name"); $result->execute(); print "<table width=\"100\%\">\n"; $i = 0; while (my @ln = $result->fetchrow_array()) { $i++; print "<tr><td width='20' onclick='settoedit(this);' id='id_$i' class='tdmy'>",@ln[4],"</td>\n"; print "<td width='25%' onclick='settoedit(this);' id='cat_$i' class='tdmy'>",@ln[0],"</td>\n"; print "<td width='25%' onclick='settoedit(this);' class='tdmy' id='name_$i'>",@ln[1],"</td>\n"; print "<td width='30%' onclick='settoedit(this);' class='tdmy' id='url_$i'>",@ln[2],"</td>\n"; print "<td> <input type='hidden' id='catid_$i' value='@ln[3]'></td></tr>\n"; } print "</table>\n"; }
Как работает инструкция SELECT ... FROM, пояснять не нужно. В процедуре в каждую ячейку таблицы мы вставим обработку события OnClick(), чтобы при щелчке на ячейке содержимое строки поместилось в поля формы (см. функцию settoedit()).
Теперь запишем данные в базу:
sub save_values { if ($data{'id'} == 0) { $linksqry = "INSERT INTO links (name,url,category) values ('".$data{'namelink'}."','" .$data{'url'}."',".$data{'category_id'}.")"; } else { $linksqry = "UPDATE links SET name='" .$data{'namelink'}."',url='".$data{'url'} ."',category=".$data{'category_id'} ." where id=".$data{'id'}; } $dbh->do($linksqry); # выполнить запрос }
Инструкция INSERT INTO table (field1,field2,field3) VALUES (val1,val2,val3) добавляет в таблицу новую запись и присваивает полям field1...fieldNN значения val1...valNN. При этом полям с атрибутом auto_increment() не пытайтесь присваивать значения — все равно MySQL будет их автонумеровать.
Инструкция UPDATE table SET field1=value1,... fieldNN=valueNN WHERE condition обновляет значения полей в записях(!), удовлетворяющих условию condition. То есть, одной инструкцией можно обновить сразу несколько записей. Например, WHERE id < 100 обновит записи с 1 по 99.
Итак, одной процедурой вносим изменения и добавляем запись, в зависимости от значения скрытого поля edit.
Следующей процедурой удаляем запись:
sub delete_record { if ($data{'id'}== 0) { # ничего не делаем!!! # если поле id == 0!!! } else { $delqry = "DELETE FROM links WHERE id = ".$data{'id'}; $dbh->do($delqry); } }
Тут все просто.
Инструкция DELETE FROM table WHERE condition удаляет все записи, удовлетворяющие условию condition. Вот таким образом можно удалить все записи, где поле URL содержит текст «sex»:
DELETE FROM links WHERE URL like '%sex%'
Вот и все. Не правда ли, просто?
Если нет желания возиться со всеми этими JavaScript’ами, то можно выводить в процедуре show_page в каждой строке таблицы форму — тогда, конечно, объем результирующего HTML-кода увеличится, но сам Perl-код заметно упростится.
И, наконец, полный текст скрипта (можно выкачать с http://shurick31.narod.ru/js/editlinks.pl.txt):
#!c:\perl\bin\perl use DBI; print "Content-type:text/html\n\n"; my $dbh = DBI->connect("DBI:mysql:database=mydb;host=localhost", "shurik", "hfbcf61") || die $DBI::errstr; print<<HTM_TOP; <head> <title>Edit links</title> <link rel="stylesheet" href="/myhome.css"> <script language="JavaScript"> function settoedit(idname) { baseid = idname.id.substring(idname.id.indexOf("_")+1); document.all['id'].value = document.all["id_"+baseid].innerHTML; document.all['category'].value = document.all["cat_"+baseid].innerHTML; document.all['category_id'].value = document.all["catid_"+baseid].value; document.all['namelink'].value = document.all["name_"+baseid].innerHTML; document.all['url'].value = document.all["url_"+baseid].innerHTML; document.all['edit'].value="edit"; } function show_hide(target) { if (document.all.Layer1.style.visibility == 'hidden') { document.all.Layer1.style.visibility = ''; } else { document.all.Layer1.style.visibility = 'hidden'; } } function setCategory() { document.all['category_id'].value = document.all['cats'].value; document.all['category'].value = document.all['cats'].options[document.all['cats'].value-1].innerHTML; } function ischange() { document.all['edit'].value="edit"; } function check_delete() { if(document.all['id'].value == '0') { alert("Выберите запись!"); } else { if (confirm("Вы хотите удалить запись №"+document.all['namelink'].value) ) { document.all['edit'].value = "delete"; document.all['frm'].submit(); } } } function check_submit() { if ((document.all['url'].value == '') || (document.all['category'].value == '' )) { alert("Введите или выберите что-нибудь!"); } else { document.all['frm'].submit(); } } </script> </head> <div id="Layer1" style="position:absolute; left:32px; top:75px; width:25%; height:120px; z-index:1; background-color: #CCCCCC; layer-background-color: #CCCCCC; border: 1px solid ; visibility: hidden"> <select name="cats" size="8" onClick="setCategory()" onDblClick = "setCategory();show_hide(this);" style="width:100%"> HTM_TOP my $res = $dbh->prepare("SELECT * FROM category ORDER by id"); $res->execute(); while (my @cln = $res->fetchrow_array()) { print "<option value='",@cln[0],"'>",@cln[1],"</option>\n"; } print<<HTML_TOP; </select> </div> <form method="POST" action="editlinks.pl" name="frm"> <input type="hidden" name="edit" value=""> <table width="100%"> <th class='thmy'>id</th> <th class='thmy'>Категория...... <input type="button" name="button" value="4" onClick="show_hide('Layer1')" title="Для выбора категории" class="tdmy" STYLE="font-family: wingdings; font-size: 12pt; color: navy; width:20"> </th> <th class='thmy'>Название</th> <th class='thmy'>Адрес</th> <tr> <td width=20> <input size=3 type="text" name="id" readonly STYLE="width=100%" onChange="ischange()" value=0> </td> <td width=25%> <input type="text" name="category" STYLE="width=100%" onChange="ischange()"> <input type="hidden" name="category_id" value=0> </td> <td width=25%> <input type="text" name="namelink" STYLE="width=100%" onChange="ischange()"> </td> <td width=30%> <input type="text" name="url" STYLE="width=100%" onChange="ischange()"> </td> <td> <input type="button" value="<" class="thmy" STYLE="font-family: wingdings; font-size: 12pt; color: navy; width:20" title="Сохранить" onClick="check_submit()"> <input type="reset" value="2" class="thmy" STYLE="font-family: wingdings; font-size: 12pt; color: navy; width:20" title="Очистить"> <input type="button" value="N" class="thmy" STYLE="font-family: wingdings; font-size: 12pt; color: navy; width:20" title="Удалить" onClick="check_delete()"> </td> </tr> </table> </form> HTML_TOP &read_input; if ($data{'edit'} eq 'edit') { &save_values; print "<h3>Изменения сохранены!</h3>\n"; &show_page; } else { if ($data{'edit'} eq 'delete') { &delete_record; } else { &show_page; } } sub show_page { my $result = $dbh->prepare("SELECT a.name as cname, b.name as name, b.url as url, a.id as catid, b.id as lid FROM category a, links b WHERE b.category=a.id ORDER by a.name"); $result->execute(); print "<table width=\"100\%\">\n"; $i = 0; while (my @ln = $result->fetchrow_array()) { $i++; print "<tr><td width='20' onclick='settoedit(this);' id='id_$i' class='tdmy'>",@ln[4],"</td>\n"; print "<td width='25%' onclick='settoedit(this);' id='cat_$i' class='tdmy'>",@ln[0],"</td>\n"; print "<td width='25%' onclick='settoedit(this);' class='tdmy' id='name_$i'>",@ln[1],"</td>\n"; print "<td width='30%' onclick='settoedit(this);' class='tdmy' id='url_$i'>",@ln[2],"</td>\n"; print "<td> <input type='hidden' id='catid_$i' value='@ln[3]'></td></tr>\n"; } print "</table>\n"; } sub save_values { if ($data{'id'} == 0) { $linksqry = "INSERT INTO links (name,url,category) values ('".$data{'namelink'}."','".$data{'url'}."',".$data{'category_id'}.")"; } else { $linksqry = "UPDATE links SET name='" .$data{'namelink'}."',url='".$data{'url'} ."',category=".$data{'category_id'}." where id=".$data{'id'}; } $dbh->do($linksqry); } sub delete_record { if ($data{'id'}== 0) { } else { $delqry = "DELETE FROM links WHERE id = ".$data{'id'}; $dbh->do($delqry); } &show_page; } sub read_input { local ($temp,@pairs); if ($ENV{'REQUEST_METHOD'} eq 'POST') { read(STDIN,$temp,$ENV{'CONTENT_LENGTH'}); } else { $temp=$ENV{'QUERY_STRING'}; } if ($temp ne '') { @pairs=split(/&/,$temp); foreach $item(@pairs) { ($key,$content)=split (/=/,$item,2); $content=~tr/+/ /; $data{$key}=$content; } return 1; } else { return 0; } }
(Продолжение следует)
