22

Editing a thread content

Create site27 by copying site26.

  1. /cms
    1. ...
    2. site26
    3. site27

In this chapter, we are going to create the thread content editor.

To test the result online, enter http://www.frasq.org/cms/site27 in the address bar of your navigator. Identify yourself with the name foobar and the password f00bar. Edit the page Legal information. Click on the name of the thread in the top right corner of the page.

NOTE: In this demonstration version, the content of the site can not be modified.

Edit the file models/thread.inc and add the functions thread_create_node, thread_delete_node and thread_set_node_number with the following contents:

  1. function thread_create_node($lang, $thread_id, $node_name, $node_title, $node_number=0) {
  2.     $tabthreadnode=db_prefix_table('thread_node');
  3.  
  4.     $sql="SELECT COUNT(*)+1 AS n FROM $tabthreadnode WHERE thread_id=$thread_id";
  5.  
  6.     $r = db_query($sql);
  7.  
  8.     if (!$r) {
  9.         return false;
  10.     }
  11.  
  12.     $n = $r[0]['n'];
  13.  
  14.     if ($node_number < 1 or $node_number > $n) {
  15.         $node_number = $n;
  16.     }
  17.  
  18.     $r = node_create($lang, $node_name, $node_title);
  19.  
  20.     if (!$r) {
  21.         return false;
  22.     }
  23.     extract($r);    /* node_id */
  24.  
  25.     if ($node_number != $n) {
  26.         $sql="UPDATE $tabthreadnode SET number=number+1 WHERE thread_id=$thread_id AND number >= $node_number ORDER BY number";
  27.  
  28.         db_update($sql);
  29.     }
  30.  
  31.     $sql="INSERT $tabthreadnode SET thread_id=$thread_id, node_id=$node_id, number=$node_number";
  32.  
  33.     $r = db_insert($sql);
  34.  
  35.     return $r ? compact('node_id', 'node_number') : false;
  36. }

thread_create_node adds a new node to thread $thread_id with $node_url as URL and $node_title as title for the language $lang. The new node is placed at position $number in the thread or, if $number isn't specified, at the end of the thread. thread_create_node returns the identifier of the new node and its position in the thread or false in case of error.

thread_create_node checks if the parameter $number is between 1 and the number of nodes in the thread plus one. If $number isn't specified or if it's invalid, the node is added at the end of the thread. Once the node has been created by node_create, if the node isn't added at the end of the thread, all the nodes following the position of the new node are shifted. thread_create_node finishes the creation of the node by adding it to the thread at the requested position.

  1. function thread_delete_node($thread_id, $node_id) {
  2.     $tabthreadnode=db_prefix_table('thread_node');
  3.  
  4.     $sql="DELETE FROM $tabthreadnode WHERE thread_id=$thread_id AND node_id=$node_id LIMIT 1";
  5.  
  6.     $r = db_delete($sql);
  7.  
  8.     if (!$r) {
  9.         return false;
  10.     }
  11.  
  12.     $sql="SET @n=0";
  13.     db_update($sql);
  14.     $sql="UPDATE $tabthreadnode SET number=(@n:=@n+1) WHERE thread_id=$thread_id ORDER BY number";
  15.     db_update($sql);
  16.  
  17.     $sql="SELECT COUNT(*) AS count FROM $tabthreadnode WHERE node_id=$node_id";
  18.  
  19.     $r = db_query($sql);
  20.  
  21.     if (!$r) {
  22.         return false;
  23.     }
  24.  
  25.     if ($r[0]['count'] != 0) {
  26.         return true;
  27.     }
  28.  
  29.     $r = node_delete($node_id);
  30.     if (!$r) {
  31.         return false;
  32.     }
  33.  
  34.     return true;
  35. }

thread_delete_node removes node $node_id from thread $thread_id and deletes it if no other thread contains it. thread_delete_node returns true or false in case of error.

thread_delete_node starts by deleting the link between the thread and the node and renumbering all the nodes of the thread. thread_delete_node then counts how many threads contain $node_id and deletes $node_id with node_delete if the answer is 0.

  1. function thread_set_node_number($thread_id, $node_id, $number) {
  2.     $tabthreadnode=db_prefix_table('thread_node');
  3.  
  4.     $sql="UPDATE $tabthreadnode SET number=$number WHERE thread_id=$thread_id AND node_id=$node_id LIMIT 1";
  5.  
  6.     $r = db_update($sql);
  7.  
  8.     return $r;
  9. }

thread_set_node_number sets the order number of node $node_id in thread $thread_id to $number.

  1.     else if (isset($_POST['thread_reorder'])) {
  2.         $action='reorder';
  3.     }
  4.     else if (isset($_POST['node_create'])) {
  5.         $action='create';
  6.     }
  7.     else if (isset($_POST['node_delete'])) {
  8.         $action='delete';
  9.     }
  1.     $new_node_name=$new_node_title=$new_node_number=false;
  2.     $old_node_number=false;
  3.  
  4.     $thread_contents = false;
  5.     $p=false;
  1.         case 'create':
  2.         case 'delete':
  3.         case 'reorder':
  1.             if (isset($_POST['new_node_title'])) {
  2.                 $new_node_title=readarg($_POST['new_node_title']);
  3.                 $new_node_name = strtofname($new_node_title);
  4.             }
  5.             if (isset($_POST['new_node_number'])) {
  6.                 $new_node_number=readarg($_POST['new_node_number']);
  7.             }
  8.             if (isset($_POST['old_node_number'])) {
  9.                 $old_node_number=readarg($_POST['old_node_number']);
  10.             }
  11.             if (isset($_POST['p'])) {
  12.                 $p=$_POST['p']; // DON'T readarg!
  13.             }
  1.     $r = thread_get_contents($clang, $thread_id, false);    /* node_id node_name node_title node_cloud node_number ... */
  2.  
  3.     if (count($p) != count($r)) {
  4.         $p = false;
  5.     }
  6.  
  7.     if ($r) {
  8.         $pos=1;
  9.         $thread_contents = array();
  10.         $thread_url = url('threadedit', $lang) . '/'. $thread_id;
  11.         foreach ($r as $c) {
  12.             $c['node_url'] = $thread_url  . '/' . $c['node_id'];
  13.             $c['pos'] = $p ? $p[$pos] : $pos;
  14.             $thread_contents[$pos] = $c;
  15.             $pos++;
  16.         }
  17.     }
  1.     $missing_new_node_title=false;
  2.     $bad_new_node_title=false;
  3.     $bad_new_node_number=false;
  4.  
  5.     $missing_old_node_number=false;
  6.     $bad_old_node_number=false;
  1.         case 'create':
  2.             if (empty($new_node_title)) {
  3.                 $missing_new_node_title = true;
  4.             }
  5.             else if (empty($new_node_name)) {
  6.                 $bad_new_node_title = true;
  7.             }
  8.             else if (!preg_match('#^[\w-]{3,}$#', $new_node_name)) {
  9.                 $bad_new_node_title = true;
  10.             }
  11.             if (empty($new_node_number)) {
  12.                 $new_node_number = false;
  13.             }
  14.             else if (!is_numeric($new_node_number)) {
  15.                 $bad_new_node_number = true;
  16.             }
  17.             else if ($new_node_number < 1 or $new_node_number > count($thread_contents) + 1) {
  18.                 $bad_new_node_number = true;
  19.             }
  20.             break;
  21.  
  22.         case 'delete':
  23.             if (empty($old_node_number)) {
  24.                 $missing_old_node_number = true;
  25.             }
  26.             else if (!is_numeric($old_node_number)) {
  27.                 $bad_old_node_number = true;
  28.             }
  29.             else if ($old_node_number < 1 or $old_node_number > count($thread_contents)) {
  30.                 $bad_old_node_number = true;
  31.             }
  32.             break;
  1.  
  2.             break;
  3.  
  4.         case 'create':
  5.             if ($missing_new_node_title or $bad_new_node_title or $bad_new_node_number) {
  6.                 break;
  7.             }
  8.  
  9.             $np = thread_create_node($clang, $thread_id, $new_node_name, $new_node_title, $new_node_number);
  10.             if (!$np) {
  11.                 break;
  12.             }
  13.  
  14.             extract($np);   /* node_id node_number node_ignored */
  15.             $node_title = $new_node_title;
  16.             $node_url = url('threadedit', $lang) . '/'. $thread_id . '/' . $node_id;
  17.             $pos = $node_number;
  18.  
  19.             if ($thread_contents) {
  20.                 foreach ($thread_contents as &$c) {
  21.                     if ($c['node_number'] >= $pos) {
  22.                         $c['node_number']++;
  23.                     }
  24.                     if ($c['pos'] >= $pos) {
  25.                         $c['pos']++;
  26.                     }
  27.                 }
  28.                 array_splice($thread_contents, $pos-1, 0, array(compact('node_id', 'node_title', 'node_number', 'node_url', 'pos')));
  29.                             }
  30.             else {
  31.                 $pos=1;
  32.                 $thread_contents=array($pos => compact('node_id', 'node_title', 'node_number', 'node_url', 'pos'));
  33.             }
  34.  
  35.             break;
  36.  
  37.         case 'delete':
  38.             if ($missing_old_node_number or $bad_old_node_number) {
  39.                 break;
  40.             }
  41.  
  42.             if (!$confirmed) {
  43.                 $confirm_delete_node=true;
  44.                 break;
  45.             }
  46.  
  47.             $node_id = $thread_contents[$old_node_number]['node_id'];
  48.  
  49.             $r = thread_delete_node($thread_id, $node_id);
  50.  
  51.             if (!$r) {
  52.                 break;
  53.             }
  54.  
  55.             unset($thread_contents[$old_node_number]);
  56.             $thread_contents = array_values($thread_contents);
  57.  
  58.             foreach ($thread_contents as &$c) {
  59.                 if ($c['node_number'] >= $old_node_number) {
  60.                     $c['node_number']--;
  61.                 }
  62.                 if ($c['pos'] >= $old_node_number) {
  63.                     $c['pos']--;
  64.                 }
  65.             }
  66.  
  67.             $old_node_number = false;
  68.  
  69.             break;
  70.  
  71.         case 'reorder':
  72.             if (!$p) {
  73.                 break;
  74.             }
  75.  
  76.             $neworder=range(1, count($p));
  77.             array_multisort($p, SORT_NUMERIC, $neworder);
  1.             $thread_contents = $nc;
  2.  
  3.             break;
  1. <h4>Contents</h4>
  2. <p>
  3. <input id="node_create" name="node_create" type="submit" value="Add" />
  4. content
  5. <input id="new_node_title" name="new_node_title" type="text" size="50" maxlength="100" value="<?php echo htmlspecialchars($new_node_title, ENT_COMPAT, 'UTF-8'); ?>" title="Title" onkeypress="return focusonenter(event, 'new_node_number')"/>
  6. #
  7. <input id="new_node_number" name="new_node_number" type="text" size="2" maxlength="3" value="<?php echo htmlspecialchars($new_node_number, ENT_COMPAT, 'UTF-8'); ?>" title="Number" onkeypress="return submitonenter(event, 'node_create')"/>
  8. </p>
  9. <?php if ($missing_new_node_title or $bad_new_node_title or $bad_new_node_number): ?>
  10. <div class="alert">
  11. <?php if ($missing_new_node_title): ?>
  12. <p>You didn't input the title of the new content.</p>
  13. <?php elseif ($bad_new_node_title): ?>
  14. <p>The title of the new content is invalid.</p>
  15. <?php endif; ?>
  16. <?php if ($bad_new_node_number): ?>
  17. <p>The new content number is not correct.</p>
  18. <?php endif; ?>
  19. </div>
  20. <?php endif; ?>
  21. <?php if ($thread_contents): ?>
  22. <fieldset>
  23. <legend>Summary</legend>
  24. <table cellpadding="2" cellspacing="0">
  25. <tbody>
  26. <?php
  27. $i=1;
  28. $maxlen=strlen(count($thread_contents))+1;
  29. foreach ($thread_contents as $c) {
  30.     extract($c);    /* pos, node_title, node_url, node_number */
  31.     $node_title = htmlspecialchars($node_title, ENT_COMPAT, 'UTF-8');
  32.     $node_url .= '?' . 'clang=' . $clang;
  33.     echo <<<_MARK_
  34. <tr><td><input name="p[$i]" type="text" size="2" maxlength="$maxlen" value="$pos" /></td><td class="aright"><a href="$node_url">$node_number</a></td><td><a href="$node_url">$node_title</a></td></tr>\n
  35. _MARK_;
  36.     $i++;
  37. }
  38. ?>
  39. </tbody>
  40. </table>
  41. </fieldset>
  42. <p>
  43. <input id="thread_reorder" name="thread_reorder" type="submit" value="Sort" />
  44. the list or
  45. <input id="node_delete" name="node_delete" type="submit" value="Delete" />
  46. content #
  47. <input id="old_node_number" name="old_node_number" type="text" size="2" maxlength="3" value="<?php echo htmlspecialchars($old_node_number, ENT_COMPAT, 'UTF-8'); ?>" title="Number" onkeypress="return submitonenter(event, 'node_delete')"/>
  48. </p>
  49. <?php if ($missing_old_node_number or $bad_old_node_number): ?>
  50. <div class="alert">
  51. <?php if ($missing_old_node_number): ?>
  52. <p>You didn't specify the content number to delete.</p>
  53. <?php elseif ($bad_old_node_number): ?>
  54. <p>The content number to delete is not correct.</p>
  55. <?php endif; ?>
  56. </div>
  57. <?php endif; ?>
  58. <?php endif; ?>
  59. </form>
  1. <h4>Contenu</h4>
  2. <p>
  3. <input id="node_create" name="node_create" type="submit" value="Ajouter" />
  4. le contenu
  5. <input id="new_node_title" name="new_node_title" type="text" size="50" maxlength="100" value="<?php echo htmlspecialchars($new_node_title, ENT_COMPAT, 'UTF-8'); ?>" title="Titre" onkeypress="return focusonenter(event, 'new_node_number')"/>
  6. #
  7. <input id="new_node_number" name="new_node_number" type="text" size="2" maxlength="3" value="<?php echo htmlspecialchars($new_node_number, ENT_COMPAT, 'UTF-8'); ?>" title="Numéro" onkeypress="return submitonenter(event, 'node_create')"/>
  8. </p>
  9. <?php if ($missing_new_node_title or $bad_new_node_title or $bad_new_node_number): ?>
  10. <div class="alert">
  11. <?php if ($missing_new_node_title): ?>
  12. <p>Vous n'avez pas saisi le titre du nouveau contenu.</p>
  13. <?php elseif ($bad_new_node_title): ?>
  14. <p>Le titre du nouveau contenu est invalide.</p>
  15. <?php endif; ?>
  16. <?php if ($bad_new_node_number): ?>
  17. <p>Le numéro du nouveau contenu n'est pas correct.</p>
  18. <?php endif; ?>
  19. </div>
  20. <?php endif; ?>
  21. <?php if ($thread_contents): ?>
  22. <fieldset>
  23. <legend>Sommaire</legend>
  24. <table cellpadding="2" cellspacing="0">
  25. <tbody>
  26. <?php
  27. $i=1;
  28. $maxlen=strlen(count($thread_contents))+1;
  29. foreach ($thread_contents as $c) {
  30.     extract($c);    /* pos, node_title, node_number, node_url */
  31.     $node_title = htmlspecialchars($node_title, ENT_COMPAT, 'UTF-8');
  32.     $node_url .= '?' . 'clang=' . $clang;
  33.     echo <<<_MARK_
  34. <tr><td><input name="p[$i]" type="text" size="2" maxlength="$maxlen" value="$pos" /></td><td class="aright"><a href="$node_url">$node_number</a></td><td><a href="$node_url">$node_title</a></td></tr>\n
  35. _MARK_;
  36.     $i++;
  37. }
  38. ?>
  39. </tbody>
  40. </table>
  41. </fieldset>
  42. <p>
  43. <input id="thread_reorder" name="thread_reorder" type="submit" value="Trier" />
  44. la liste ou
  45. <input id="node_delete" name="node_delete" type="submit" value="Supprimer" />
  46. le contenu #
  47. <input id="old_node_number" name="old_node_number" type="text" size="2" maxlength="3" value="<?php echo htmlspecialchars($old_node_number, ENT_COMPAT, 'UTF-8'); ?>" title="Numéro" onkeypress="return submitonenter(event, 'node_delete')"/>
  48. </p>
  49. <?php if ($missing_old_node_number or $bad_old_node_number): ?>
  50. <div class="alert">
  51. <?php if ($missing_old_node_number): ?>
  52. <p>Vous n'avez pas saisi le numéro du contenu à supprimer.</p>
  53. <?php elseif ($bad_old_node_number): ?>
  54. <p>Le numéro du contenu à supprimer est incorrect.</p>
  55. <?php endif; ?>
  56. </div>
  57. <?php endif; ?>
  58. <?php endif; ?>
  59. </form>

Comments

To add a comment, click here.