<pedrocorreia.net ⁄>
corner
<mySearch ⁄> <mySearch ⁄>

corner
 
corner
<mySnippets order="rand" ⁄> <mySnippets order="rand" ⁄>

corner
 
corner
<myContacts ⁄> <myContacts ⁄>

<email ⁄>


pc@pedrocorreia.net

<windows live messenger ⁄>


pedrojacorreia@hotmail.com

<myCurriculum type="pdf" ⁄>


Download
corner
 
corner
<myBlog show="last" ⁄> <myBlog show="last" ⁄>

corner
 
corner
<myNews show="rand" ⁄> <myNews show="rand" ⁄>

corner
 
corner
<myNews type="cat" ⁄> <myNews type="cat" ⁄>

corner
 
corner
<myQuote order="random" ⁄> <myQuote order="random" ⁄>

corner
 
corner
<myPhoto order="random" ⁄> <myPhoto order="random" ⁄>

<pedrocorreia.net ⁄>
corner
 
corner
<myAdSense ⁄> <myAdSense ⁄>

corner
 
corner
<myVisitorsMap ⁄> <myVisitorsMap ⁄>

corner
 
 

<Construir FAQ usando PHP+Ajax ⁄ >




clicks: 10924 10924 2007-05-27 2007-05-27 goto mySnippets mySnippets php  Download  Bookmark This Bookmark This



Uma FAQ bem estruturada e de fácil utilização é meio caminho andado para que os utilizadores do(s) nosso(s) serviço(s) percebam e consigam interagir com o(s) mesmo(s), tirando partido das capacidades e efectuar as operações fornecidas e/ou entender a informação correctamente e dar-lhe o uso mais adequado e por nós pretendido.



Num snippet anterior tinha dado um exemplo de como construir menus em árvores de uma forma dinâmica, como base neste snippet vou ter a árvore, visto que será essa a forma como irá ser construida a FAQ (o principal objectivo do snippet é constuir uma faq, mas claro que pode ser aproveitado para construir outro tipo de aplicação com objectivos completamente diferentes). Consultem esse snippet para que possam perceber a mecânica da construção da árvore.



Comecemos pelo css, terá o nome de style.css:
  1. /******* <estrutura e layout> *******/
  2. body{
  3. font-family: Tahoma, Verdana, Arial, sans-serif;
  4. font-size: 8pt;color: #000000;margin: 2px;
  5. padding: 0;background: #6E726C;text-align: center;
  6. }
  7. .container{
  8. position: relative;clear: both;width: auto;height: auto;
  9. margin: 0px;padding: 1px;background: #ffffff;color: #000000;
  10. text-align: left;border: 1px solid #2F5B0C;
  11. }
  12.  
  13. .div_faq{
  14. position: relative;float: left;
  15. width: 250px;margin: 2px 2px 5px 2px;
  16. padding: 2px;height: 500px;overflow: auto;
  17. }
  18.  
  19. .div_faq_note{
  20. position: static;width: auto;padding: 2px;margin: 0;
  21. border: solid 1px #2F5B0C;height: 500px;overflow: auto;
  22. }
  23.  
  24. .div_faq_note a{color: #FF5604;text-decoration: none;}
  25. .div_faq_note a:hover{color: #FF5604;text-decoration: underline;}
  26.  
  27. .div_content{position: static;overflow: auto;width: auto;}
  28. .content{
  29. color: #000000;font-family: Tahoma, Verdana, Arial, sans-serif;
  30. font-size: 8pt;padding: 2px;margin: 0;border: solid 1px #2F5B0C;
  31. }
  32.  
  33. a{color: #FF5604;text-decoration: underline;}
  34. a:hover{color: #E39243;text-decoration: none;}
  35. img{border: none;}
  36.  
  37. .title{
  38. font-family: Verdana, Tahoma, Arial, sans-serif;color: #ffffff;
  39. background-color: #00B200;font-variant: small-caps;
  40. border: solid 1px #6E726C;margin: 0px;padding: 1px;
  41. }
  42. .orange{color: #FF5604;}
  43.  
  44.  





Vamos criar alguns settings (dados da bd, mensagens) utilizando um ficheiro à parte, vamos chamar-lhe settings.inc:
  1. <?php
  2. //constantes da bd
  3. define("TBL_FAQ","dados_faq");
  4. define("TBL_FIELD_ID","id");
  5. define("TBL_FIELD_BELONGS_TO","pertence");
  6. define("TBL_FIELD_DESCRIPTION","descricao");
  7.  
  8.  
  9. //mensagens
  10. define("LNG_FAQ_TREE_TITLE","Perguntas Frequentes");
  11. define("LNG_FAQ_LOCAL","Localização");
  12. define("LNG_FAQ_ANSWER_TITLE","Resposta");
  13. define("LNG_FAQ_ANSWER_NONE_SELECTED","(selecione uma pergunta no menu do lado esquerdo)");
  14.  
  15. //definições de ligação à bd
  16. define("DB_SERVER","localhost");
  17. define("DB_USERNAME","root");
  18. define("DB_PASSWORD","");
  19. define("DB_NAME","database");
  20. ?>





O core da aplicação vai estar no seguinte ficheiro (funcoes_faq.php), aqui vão estar todos os métodos necessários para o funcionamento da aplicação:
  1. <?php
  2. include_once("settings.inc");
  3.  
  4. function DoFAQ(){
  5. $treemenu=DoFAQMenu(TBL_FAQ,"faqTreeview","tree2");
  6. return $treemenu;
  7. }
  8.  
  9. /**
  10. * Construir menu faq e div resposta
  11. *
  12. * @param String $table
  13. * @param String $treeName
  14. * @param String $div
  15. * @param String $fieldID
  16. * @param String $fieldBelongsTo
  17. * @param String $fieldDescription
  18. * @return String
  19. */
  20. function DoFAQMenu($table,$treeName,$div,$fieldID=TBL_FIELD_ID,$fieldBelongsTo=TBL_FIELD_BELONGS_TO,$fieldDescription=TBL_FIELD_DESCRIPTION){
  21. $db=connectDB();
  22.  
  23. $sql=mysql_query("
  24. Select Distinct r1.$fieldID,r1.$fieldDescription,r1.$fieldBelongsTo,count(r1.$fieldBelongsTo) as countSubNos
  25. From $table as r1
  26. Inner Join $table AS r2 On r1.$fieldID = r2.$fieldBelongsTo
  27. Group By r1.$fieldID
  28. Order By r1.$fieldBelongsTo, r1.$fieldDescription Asc
  29. ") or die(mysql_error());
  30.  
  31. while($myrow=mysql_fetch_array($sql)){
  32. $idLink=($myrow["countSubNos"]==1)?$myrow["$fieldID"]:"";
  33. $content.=DoMenuNode($treeName,$myrow["$fieldID"],$myrow["$fieldDescription"],$myrow["$fieldBelongsTo"],$idLink);
  34. }
  35. mysql_close($db);
  36.  
  37. $menu="
  38. var $treeName=new jktreeview(\"$div\");\r\n
  39. $content
  40. $treeName.treetop.draw(); //REQUIRED LINE: Initalize tree\r\n
  41. ";
  42.  
  43. $menu="<div id=\"$div\"></div><script type=\"text/javascript\">$menu</script>";
  44.  
  45. $divMenuFAQ="<div id=\"divMenuFAQ\" $attributes class='div_faq content'>";
  46. $divMenuFAQ.="<span class='title'>".LNG_FAQ_TREE_TITLE."</span>$menu</div>";
  47.  
  48. $divMenuFAQNotes="<div id=\"divMenuFAQNotes\" class=\"div_faq_note\">";
  49. $divMenuFAQNotes.="<span class='title'>".LNG_FAQ_ANSWER_TITLE."</span>";
  50. $divMenuFAQNotes.="<br><br>".LNG_FAQ_ANSWER_NONE_SELECTED."</div>";
  51.  
  52. return $divMenuFAQ.$divMenuFAQNotes;
  53. }
  54.  
  55. /**
  56. * Construir nó (função auxiliar da função DoMenu)
  57. *
  58. * @param String $treeName
  59. * @param int $nodeNumber
  60. * @param String $nodeDescription
  61. * @param int $nodeBelongsTo
  62. * @param String $nodeLink
  63. * @return String
  64. */
  65. function DoMenuNode($treeName,$nodeNumber,$nodeDescription,$nodeBelongsTo,$nodeLink=""){
  66. $prefixNode="node";
  67. $nodeBelongsTo=($nodeBelongsTo>0)?"$prefixNode$nodeBelongsTo":"\"\"";
  68. $nodeLink=($nodeLink)?(",\"javascript:ajaxShowFAQAnswer('$nodeLink')\""):"";
  69.  
  70. return "var $prefixNode$nodeNumber=$treeName.addItem(\"$nodeDescription\",$nodeBelongsTo $nodeLink);\r\n";
  71. }
  72.  
  73.  
  74. /**
  75. * Obter "caminho" até ao item a ser visto
  76. *
  77. * @param int $key
  78. * @return String
  79. */
  80. function GetLocalizacao($key){return DoLocalizacao($key);}
  81.  
  82. /**
  83. * Obter localização do item
  84. *
  85. * @param int $pertence
  86. * @param Array $arr
  87. * @param String $fieldID
  88. * @param String $fieldBelongsTo
  89. * @param String $fieldDescription
  90. * @return String
  91. */
  92. function DoLocalizacao($pertence,$arr="",$fieldID=TBL_FIELD_ID,$fieldBelongsTo=TBL_FIELD_BELONGS_TO,$fieldDescription=TBL_FIELD_DESCRIPTION){
  93. if(!is_array($arr)){$arr=array();}
  94.  
  95. if($pertence==0) {
  96. $separador=buildImage("expand.png","Tópico ...");
  97. return implode(" $separador ",array_reverse($arr));
  98. }
  99.  
  100. $value=getValueFromTable(TBL_FAQ,$fieldDescription,$fieldID,$pertence);
  101. $pertence=getValueFromTable(TBL_FAQ,$fieldBelongsTo,$fieldID,$pertence);
  102.  
  103. array_push($arr,$value);
  104. return DoLocalizacao($pertence,$arr,$fieldID,$fieldBelongsTo,$fieldDescription);
  105. }
  106.  
  107.  
  108. /**
  109. * Obter resposta e construir conteúdo do div
  110. *
  111. * @param int $key
  112. * @return String
  113. */
  114. function GetFAQAnswer($key){
  115. $allowedHtmlTags="<table><tr><td><br><br/><b><i><u><a><p>";
  116. $str="<span class='title'>".LNG_FAQ_LOCAL."</span><br/><br/>";
  117. $str.="<span class='orange'>".GetLocalizacao($key)."</span><br/><br/>";
  118. $str.="<span class='title'>".LNG_FAQ_ANSWER_TITLE."</span><br/><br/>";
  119. $str.=strip_tags(getValueFromTable(TBL_FAQ,"descricao","pertence",$key),$allowedHtmlTags);
  120. return utf8_encode($str);
  121. }
  122.  
  123.  
  124.  
  125. //funções auxiliares
  126. /**
  127. * Obter valor da tabela
  128. *
  129. * @param String $tabela
  130. * @param String $campoAObter
  131. * @param String $id_filter
  132. * @param String $filter_value
  133. * @return String
  134. */
  135. function getValueFromTable($tabela, $campoAObter,$id_filter, $filter_value){
  136. $db=connectDB();
  137. $sql="SELECT $campoAObter FROM $tabela WHERE $id_filter='$filter_value'";
  138. $myRes = mysql_query($sql) or die("$sql ".mysql_error());
  139. $myrow=mysql_fetch_assoc($myRes);
  140. $fieldValue=$myrow["$campoAObter"];
  141. mysql_close($db);
  142. return $fieldValue;
  143. }
  144.  
  145. /**
  146. * Construir imagem
  147. *
  148. * @param String $file
  149. * @param String $texto
  150. * @param String $name
  151. * @param String $attributes
  152. * @param String $path
  153. * @return String
  154. */
  155. function buildImage($file,$description,$name="",$attributes="",$path="."){
  156. if($name) $name=" id='$name' name='$name' ";
  157. return "<img src='$path/$file' border='0' alt='$description' title='$description' longdesc='$description' $attributes $name>";
  158. }
  159. /**
  160. * Fazer ligação à bd
  161. *
  162. * @return identificador
  163. */
  164. function connectDB(){
  165. $db = mysql_connect(DB_SERVER,DB_USERNAME,DB_PASSWORD);
  166. mysql_select_db(DB_NAME,$db) or die("<b><br/>Impossivel aceder á base de dados.</b><br/>");
  167. return $db;
  168. }
  169.  
  170. ?>




Tinha mencionado no titulo que iria ser utilizado o AJAX, isto vai tornar a aplicação muito mais fluida sem que seja preciso a página estar constantemente a ser carregada, como todos os custos de performance e sobre-carregamento do servidor, inerentes à construção da página, ou seja basicamente, apenas uma determinada parte da página irá ser alterada, se ainda não entendem bem o AJAX, sugiro vivamente que procurem informações, visto que é uma tecnologia interessante.


Vamos então construir a parte relativa ao AJAX. Vão existir 2 ficheiros nesta abordagem, ajax.js e ajax.php.


- ajax.js -> vai ser responsável pela criação do request, comunicação com o servidor (efectuar pedido e processar resposta) e actualizar o conteúdo, como poderão ver no código, como pequena curiosidade, enquanto o ajax.js "fica à espera" que o ciclo de comunicação termine e seja devolvido com sucesso a resposta ao seu pedido, vai existir uma informação de loading, poderão ver algumas animações de loading neste site (ajax indicators).
  1. var http_request = false;
  2. /**
  3. * Mensagem a mostrar ao utilizador enquanto a informação estiver a ser carregada
  4. *
  5. */
  6. function MsgLoading(){
  7. var msg_loading="A carregar informação ...";
  8. var img_loading="<img src='loading_bar.gif' width='51' height='19' alt='"+msg_loading+"' title='"+msg_loading+"'>";
  9. return "<span class='title''>"+msg_loading+"</span><br/><br/>"+img_loading;
  10. }
  11.  
  12. /**
  13. * Criar request
  14. *
  15. */
  16. function createHttpRequest(){
  17. if (window.XMLHttpRequest){ // Mozilla, Safari,...
  18. http_request = new XMLHttpRequest();
  19.  
  20. if (http_request.overrideMimeType){
  21. http_request.overrideMimeType('text/html');
  22. }
  23. }
  24. else if (window.ActiveXObject){ // IE
  25. try{
  26. http_request = new ActiveXObject("Msxml2.XMLHTTP");
  27. }
  28. catch (e){
  29. try{
  30. http_request = new ActiveXObject("Microsoft.XMLHTTP");
  31. }
  32. catch (e) {}
  33. }
  34. }
  35. if (!http_request){
  36. alert('Giving up :( Cannot create an XMLHTTP instance');
  37. return false;
  38. }
  39. }
  40.  
  41. /**
  42. * Método responsável pelo inicio da comunicação com o servidor
  43. *
  44. * @param int id_question
  45. */
  46. function ajaxShowFAQAnswer(id_question){
  47. var div="divMenuFAQNotes";
  48.  
  49. url = antiCacheRand("ajax.php?accao=get_faq&key="+id_question);
  50. createHttpRequest();
  51.  
  52. http_request.onreadystatechange = function() {
  53. updateContent(div);
  54. };
  55.  
  56. http_request.open("GET", url, true);
  57. http_request.send(null);
  58. }
  59.  
  60. /**
  61. * Obter a resposta e fazer o tratamento necessário
  62. *
  63. * @param String div
  64. *
  65. */
  66. function updateContent(div){
  67. var state=http_request.readyState;
  68. setContentDiv(div,MsgLoading());
  69.  
  70. switch(state){
  71. case 4: //completo
  72. if (http_request.status == 200){ //pedido respondido com sucesso
  73. setContentDiv(div,http_request.responseText);
  74. }
  75. else{
  76. setContentDiv(div,'Erro! Tente novamente');
  77. }
  78. break;
  79. }
  80. }
  81.  
  82. // hack IE para ultrapassar problema cache pedidos get
  83. function antiCacheRand(aurl) {
  84. var foo=encodeURI(Math.random());
  85. aurl+=(aurl.indexOf("?")>=0)?"&foo="+foo:"?foo="+foo;
  86. return aurl;
  87. }
  88.  
  89. /**
  90. * Construir menu faq e div resposta
  91. *
  92. * @param String div_name
  93. * @param String content
  94. *
  95. */
  96. function setContentDiv(div_name, content){
  97. var div=document.getElementById(div_name);
  98. if(div){
  99. div.innerHTML=unescape(content);
  100. }
  101. }








- ajax.php -> vai processar o pedido efectuado pelo ajax.js, vai comunicar com a BD para devolver a informação pretendida;
  1. <?php
  2. include_once("funcoes_faq.php");
  3. include_once("settings.inc");
  4.  
  5. $accao=$_REQUEST["accao"];
  6.  
  7. if ($accao=="get_faq"){
  8. $key=$_REQUEST["key"];
  9.  
  10. if(!is_numeric($key)){
  11. echo LNG_FAQ_ANSWER_NONE_SELECTED;
  12. }
  13. else{
  14. echo GetFAQAnswer($key);
  15. }
  16. }
  17. ?>





Por fim, o ficheiro que vai "colar" as peças todas e que o utilizador irá digitar na barra de endereços, faq.php:
  1. <?php
  2. include_once("funcoes_faq.php");
  3. ?>
  4. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
  5. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt">
  6. <head>
  7. <link rel="stylesheet" type="text/css" href="style.css" media="screen" />
  8. <script type='text/javascript' src='ajax.js'></script>
  9.  
  10. <link rel="stylesheet" type="text/css" href="foldingtreeview/css/multi/tree.css">
  11. <script type="text/javascript" src="foldingtreeview/build/yahoo.js" ></script>
  12. <script type="text/javascript" src="foldingtreeview/build/event.js"></script>
  13. <script type="text/javascript" src="foldingtreeview/build/treeview.js" ></script>
  14. <script type="text/javascript" src="foldingtreeview/build/jktreeview.js" ></script>
  15.  
  16. <title>Construir FAQ usando Ajax</title>
  17. </head>
  18. <body>
  19. <div class="container">
  20. <div class="div_content"><!-- inicio content -->
  21. <?php
  22. echo DoFAQ();
  23. ?>
  24. </div><!-- fim content -->
  25. </div>
  26. </body>
  27. </html>
  28.  
  29.  




nota: se a árvore tiver pouca informação o utilizador conseguirá perceber facilmente em que posição é que se encontra a informação a ser visualizada, no entanto quando a árvore começar a crescer, isso tornar-se-á mais complicado, para que o utilizador tenha saiba rapidamente qual a informação que está a visualizar foi construído um método (ver funcoes_faq.php) que devolve a localização exacta do nó que está a ser visto.


Aqui fica um exemplo ...


Qualquer erro/ dúvida é só dizer!









clicks: 10924 10924 2007-05-27 2007-05-27 goto mySnippets mySnippets php  Download  Bookmark This Bookmark This