From 90df9a4d69a2e467433b419b94fe799d11590539 Mon Sep 17 00:00:00 2001
From: Adrian Lang <lang@cosmocode.de>
Date: Thu, 4 Feb 2010 14:50:10 +0100
Subject: [PATCH] Rewrite section edit handling according to #1860

---
 .../cases/inc/parser/parser_footnote.test.php |  4 +-
 .../cases/inc/parser/parser_headers.test.php  | 21 -----
 _test/cases/inc/parser/parser_i18n.test.php   |  6 +-
 _test/cases/inc/parser/parser_table.test.php  | 52 ++++++------
 inc/html.php                                  | 21 +++--
 inc/lang/en/lang.php                          |  1 +
 inc/parser/handler.php                        | 32 ++------
 inc/parser/renderer.php                       |  6 +-
 inc/parser/xhtml.php                          | 81 ++++++++++++++-----
 lib/scripts/script.js                         | 42 ++++------
 10 files changed, 120 insertions(+), 146 deletions(-)

diff --git a/_test/cases/inc/parser/parser_footnote.test.php b/_test/cases/inc/parser/parser_footnote.test.php
index 08d199182..a1da2ab06 100644
--- a/_test/cases/inc/parser/parser_footnote.test.php
+++ b/_test/cases/inc/parser/parser_footnote.test.php
@@ -259,7 +259,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
             array('cdata',array("\n".'Foo ')),
             array('nest', array ( array (
               array('footnote_open',array()),
-              array('table_open',array(3,2)),
+              array('table_open',array(3, 2, 8)),
               array('tablerow_open',array()),
               array('tablecell_open',array(1,'left',1)),
               array('cdata',array(' Row 0 Col 1    ')),
@@ -282,7 +282,7 @@ class TestOfDoku_Parser_Footnote extends TestOfDoku_Parser {
               array('cdata',array(' Row 1 Col 3        ')),
               array('tablecell_close',array()),
               array('tablerow_close',array()),
-              array('table_close',array(8, 123)),
+              array('table_close',array(123)),
               array('cdata',array(' ')),
               array('footnote_close',array()),
             ))),
diff --git a/_test/cases/inc/parser/parser_headers.test.php b/_test/cases/inc/parser/parser_headers.test.php
index 8e6517123..e1c6783f5 100644
--- a/_test/cases/inc/parser/parser_headers.test.php
+++ b/_test/cases/inc/parser/parser_headers.test.php
@@ -15,14 +15,12 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nabc \n")),
             array('p_close',array()),
-            array('section_edit',array(-1,5,1,'')),
             array('header',array('Header',1,6)),
             array('section_open',array(1)),
             array('p_open',array()),
             array('cdata',array("\n def\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array (6,0,1,'Header')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
@@ -36,14 +34,12 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nabc \n")),
             array('p_close',array()),
-            array('section_edit',array(-1,5,1,'')),
             array('header',array('Header',2,6)),
             array('section_open',array(2)),
             array('p_open',array()),
             array('cdata',array("\n def\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(6,0,2,'Header')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
@@ -57,14 +53,12 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nabc \n")),
             array('p_close',array()),
-            array('section_edit',array(-1,5,1,'')),
             array('header',array('Header',3,6)),
             array('section_open',array(3)),
             array('p_open',array()),
             array('cdata',array("\n def\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(6,0,3,'Header')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
@@ -116,14 +110,12 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nabc \n")),
             array('p_close',array()),
-            array('section_edit',array(-1,5,1,'')),
             array('header',array('Header',2,6)),
             array('section_open',array(2)),
             array('p_open',array()),
             array('cdata',array("\n def\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(6,0,2,'Header')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
@@ -137,14 +129,12 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nabc \n")),
             array('p_close',array()),
-            array('section_edit',array(-1,5,1,'')),
             array('header',array('Header',2,6)),
             array('section_open',array(2)),
             array('p_open',array()),
             array('cdata',array("\n def\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(6,0,2,'Header')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
@@ -158,14 +148,12 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nabc \n")),
             array('p_close',array()),
-            array('section_edit',array(-1,5,1,'')),
             array('header',array('Header',1,6)),
             array('section_open',array(1)),
             array('p_open',array()),
             array('cdata',array("\n def\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(6,0,1,'Header')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
@@ -193,14 +181,12 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nabc \n")),
             array('p_close',array()),
-            array('section_edit',array(-1,5,1,'')),
             array('header',array('== Header ==',1,6)),
             array('section_open',array(1)),
             array('p_open',array()),
             array('cdata',array("\n def\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(6,0,1,'== Header ==')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
@@ -233,14 +219,12 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nabc \n== ====== Header\n")),
             array('p_close',array()),
-            array('section_edit',array(-1,22,1,'')),
             array('header',array('',1,23)),
             array('section_open',array(1)),
             array('p_open',array()),
             array('cdata',array("\n def\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(23,0,1,'')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
@@ -261,14 +245,12 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array('abc '.DOKU_PARSER_EOL)),
             array('p_close',array()),
-            array('section_edit',array(-1,5,1,'')),
             array('header',array('Header',1, 6)),
             array('section_open',array(1)),
             array('p_open',array()),
             array('cdata',array(' def'.DOKU_PARSER_EOL)),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(6,0,1,'Header')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
@@ -283,21 +265,18 @@ class TestOfDoku_Parser_Headers extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nabc \n")),
             array('p_close',array()),
-            array('section_edit',array(-1,5,1,'')),
             array('header',array('Header',1,6)),
             array('section_open',array(1)),
             array('p_open',array()),
             array('cdata',array("\n def abc \n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(6,38,1,'Header')),
             array('header',array('Header2',2,39)),
             array('section_open',array(2)),
             array('p_open',array()),
             array('cdata',array("\n def\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(39,0,2,'Header2')),
             array('document_end',array())
         );
         $this->assertEqual(array_map('stripByteIndex',$this->H->calls),$calls);
diff --git a/_test/cases/inc/parser/parser_i18n.test.php b/_test/cases/inc/parser/parser_i18n.test.php
index e97a0cf51..f0cceb69e 100644
--- a/_test/cases/inc/parser/parser_i18n.test.php
+++ b/_test/cases/inc/parser/parser_i18n.test.php
@@ -62,14 +62,12 @@ class TestOfDoku_Parser_i18n extends TestOfDoku_Parser {
             array('p_open',array()),
             array('cdata',array("\nFoo\n")),
             array('p_close',array()),
-            array('section_edit',array(-1,4,1,'')),
             array('header',array('Iñtërnâtiônàlizætiøn',3,5)),
             array('section_open',array(3)),
             array('p_open',array()),
             array('cdata',array("\n Bar\n")),
             array('p_close',array()),
             array('section_close',array()),
-            array('section_edit',array(5,0,3,'Iñtërnâtiônàlizætiøn')),
             array('document_end',array()),
         );
         $this->assertEqual(array_map('stripbyteindex',$this->H->calls),$calls);
@@ -87,7 +85,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,2)),
+            array('table_open',array(3, 2, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'left',1)),
             array('cdata',array(' Row 0 Col 1    ')),
@@ -110,7 +108,7 @@ def');
             array('cdata',array(' Row 1 Col 3        ')),
             array('tablecell_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 153)),
+            array('table_close',array(153)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
diff --git a/_test/cases/inc/parser/parser_table.test.php b/_test/cases/inc/parser/parser_table.test.php
index 981f85217..099909495 100644
--- a/_test/cases/inc/parser/parser_table.test.php
+++ b/_test/cases/inc/parser/parser_table.test.php
@@ -19,7 +19,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,2)),
+            array('table_open',array(3, 2, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'left',1)),
             array('cdata',array(' Row 0 Col 1    ')),
@@ -42,7 +42,7 @@ def');
             array('cdata',array(' Row 1 Col 3        ')),
             array('tablecell_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 121)),
+            array('table_close',array(121)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -59,7 +59,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,2)),
+            array('table_open',array(3, 2, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'left',1)),
             array('cdata',array(' Row 0 Col 1    ')),
@@ -82,7 +82,7 @@ def');
             array('cdata',array(' Row 1 Col 3        ')),
             array('tablecell_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 121)),
+            array('table_close',array(121)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -103,10 +103,10 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(0,1)),
+            array('table_open',array(0, 1, 6)),
             array('tablerow_open',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 7)),
+            array('table_close',array(7)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -128,7 +128,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,1)),
+            array('table_open',array(3, 1, 6)),
             array('tablerow_open',array()),
             array('tableheader_open',array(1,NULL,1)),
             array('cdata',array(' X ')),
@@ -140,7 +140,7 @@ def');
             array('cdata',array(' Z ')),
             array('tableheader_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 19)),
+            array('table_close',array(19)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -163,7 +163,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,1)),
+            array('table_open',array(3, 1, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'right',1)),
             array('cdata',array('  X ')),
@@ -175,7 +175,7 @@ def');
             array('cdata',array('  Z  ')),
             array('tableheader_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 23)),
+            array('table_close',array(23)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -199,7 +199,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,3)),
+            array('table_open',array(3, 3, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(2,'right',1)),
             array('cdata',array('  d ')),
@@ -218,7 +218,7 @@ def');
             array('tablerow_close',array()),
             array('tablerow_open',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 31)),
+            array('table_close',array(31)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -241,7 +241,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,3)),
+            array('table_open',array(3, 3, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,NULL,2)),
             array('cdata',array(' a ')),
@@ -266,7 +266,7 @@ def');
             array('cdata',array(':::f')),
             array('tablecell_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 51)),
+            array('table_close',array(51)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -288,7 +288,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,1)),
+            array('table_open',array(3, 1, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'right',1)),
             array('cdata',array('  ')),
@@ -304,7 +304,7 @@ def');
             array('cdata',array('  Z  ')),
             array('tableheader_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 27)),
+            array('table_close',array(27)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -328,7 +328,7 @@ def');
             array('p_open',array()),
             array('cdata',array(DOKU_PARSER_EOL."abc")),
             array('p_close',array()),
-            array('table_open',array(3,2)),
+            array('table_open',array(3, 2, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'left',1)),
             array('cdata',array(' Row 0 Col 1    ')),
@@ -351,7 +351,7 @@ def');
             array('cdata',array(' Row 1 Col 3        ')),
             array('tablecell_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 121)),
+            array('table_close',array(121)),
             array('p_open',array()),
             array('cdata',array('def'.DOKU_PARSER_EOL)),
             array('p_close',array()),
@@ -375,7 +375,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,2)),
+            array('table_open',array(3, 2, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'left',1)),
             array('cdata',array(' ')),
@@ -403,7 +403,7 @@ def');
             array('cdata',array(' Row 1 Col 3        ')),
             array('tablecell_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 129)),
+            array('table_close',array(129)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -427,7 +427,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,2)),
+            array('table_open',array(3, 2, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'left',1)),
             array('cdata',array(' ')),
@@ -451,7 +451,7 @@ def');
             array('cdata',array(' Row 1 Col 3        ')),
             array('tablecell_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 155)),
+            array('table_close',array(155)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -473,7 +473,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,2)),
+            array('table_open',array(3, 2, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'left',1)),
             array('cdata',array(' Row 0')),
@@ -498,7 +498,7 @@ def');
             array('cdata',array(' Row 1 Col 3        ')),
             array('tablecell_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 123)),
+            array('table_close',array(123)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
@@ -523,7 +523,7 @@ def');
             array('p_open',array()),
             array('cdata',array("\n\nabc")),
             array('p_close',array()),
-            array('table_open',array(3,2)),
+            array('table_open',array(3, 2, 6)),
             array('tablerow_open',array()),
             array('tablecell_open',array(1,'left',1)),
             array('cdata',array(' ')),
@@ -555,7 +555,7 @@ def');
             array('cdata',array(' Row 1 Col 3        ')),
             array('tablecell_close',array()),
             array('tablerow_close',array()),
-            array('table_close',array(6, 129)),
+            array('table_close',array(129)),
             array('p_open',array()),
             array('cdata',array('def'."\n")),
             array('p_close',array()),
diff --git a/inc/html.php b/inc/html.php
index 8a215f440..a6ec628cf 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -91,22 +91,19 @@ function html_secedit_button($matches){
     global $ID;
     global $INFO;
 
-    $edittarget = ($matches[1] === 'SECTION') ? 'plain' :
-                  strtolower($matches[1]);
+    $nr = $matches[1];
+    $target = strtolower($matches[2]);
 
-    $section = $matches[3];
-    $name = $matches[2];
+    $name = $matches[3];
+    $section = $matches[4];
 
-    $secedit  = '';
-    $secedit .= '<div class="secedit editbutton_' . $edittarget . '">';
-    $secedit .= html_btn('secedit',$ID,'',
+    return "<div class='secedit editbutton_$target editbutton_$nr'>" .
+               html_btn('secedit',$ID,'',
             array('do'      => 'edit',
                 'lines'   => $section,
-                'edittarget' => $edittarget,
+                'edittarget' => $target,
                 'rev' => $INFO['lastmod']),
-            'post', $name);
-    $secedit .= '</div>';
-    return $secedit;
+            'post', $name) . '</div>';
 }
 
 /**
@@ -117,7 +114,7 @@ function html_secedit_button($matches){
 function html_secedit($text,$show=true){
     global $INFO;
 
-    $regexp = '#<!-- ([A-Z]+) (?:"(.*)" )?\[(\d+-\d*)\] -->#';
+    $regexp = '#<!-- EDIT(\d+) ([A-Z]+) (?:"([^"]*)" )?\[(\d+-\d*)\] -->#';
 
     if($INFO['writable'] && $show && !$INFO['rev']){
         $text = preg_replace_callback($regexp,
diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php
index 98ded12ca..3062d1724 100644
--- a/inc/lang/en/lang.php
+++ b/inc/lang/en/lang.php
@@ -152,6 +152,7 @@ $lang['external_edit'] = 'external edit';
 $lang['summary']    = 'Edit summary';
 $lang['noflash']    = 'The <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> is needed to display this content.';
 $lang['download']   = 'Download Snippet';
+$lang['table_edit_title'] = 'Table';
 
 $lang['mail_newpage']  = 'page added:';
 $lang['mail_changed']  = 'page changed:';
diff --git a/inc/parser/handler.php b/inc/parser/handler.php
index 141cbcaf0..b5d2baaab 100644
--- a/inc/parser/handler.php
+++ b/inc/parser/handler.php
@@ -12,9 +12,6 @@ class Doku_Handler {
 
     var $status = array(
         'section' => false,
-        'section_edit_start' => -1,
-        'section_edit_level' => 1,
-        'section_edit_title' => ''
     );
 
     var $rewriteBlocks = true;
@@ -40,10 +37,6 @@ class Doku_Handler {
         if ( $this->status['section'] ) {
            $last_call = end($this->calls);
            array_push($this->calls,array('section_close',array(), $last_call[2]));
-           if ($this->status['section_edit_start']>1) {
-               // ignore last edit section if there is only one header
-               array_push($this->calls,array('section_edit',array($this->status['section_edit_start'], 0, $this->status['section_edit_level'], $this->status['section_edit_title']), $last_call[2]));
-           }
         }
 
         if ( $this->rewriteBlocks ) {
@@ -97,8 +90,6 @@ class Doku_Handler {
     }
 
     function header($match, $state, $pos) {
-        global $conf;
-
         // get level and title
         $title = trim($match);
         $level = 7 - strspn($title,'=');
@@ -108,13 +99,6 @@ class Doku_Handler {
 
         if ($this->status['section']) $this->_addCall('section_close',array(),$pos);
 
-        if ($level<=$conf['maxseclevel']) {
-            $this->_addCall('section_edit',array($this->status['section_edit_start'], $pos-1, $this->status['section_edit_level'], $this->status['section_edit_title']), $pos);
-            $this->status['section_edit_start'] = $pos;
-            $this->status['section_edit_level'] = $level;
-            $this->status['section_edit_title'] = $title;
-        }
-
         $this->_addCall('header',array($title,$level,$pos), $pos);
 
         $this->_addCall('section_open',array($level),$pos);
@@ -583,17 +567,16 @@ class Doku_Handler {
                 $ReWriter = new Doku_Handler_Table($this->CallWriter);
                 $this->CallWriter = & $ReWriter;
 
-                $this->_addCall('table_start', array(), $pos);
+                $this->_addCall('table_start', array($pos + 1), $pos);
                 if ( trim($match) == '^' ) {
                     $this->_addCall('tableheader', array(), $pos);
                 } else {
                     $this->_addCall('tablecell', array(), $pos);
                 }
-                $this->status['table_begin'] = $pos;
             break;
 
             case DOKU_LEXER_EXIT:
-                $this->_addCall('table_end', array($this->status['table_begin']+1, $pos), $pos);
+                $this->_addCall('table_end', array($pos), $pos);
                 $this->CallWriter->process();
                 $ReWriter = & $this->CallWriter;
                 $this->CallWriter = & $ReWriter->CallWriter;
@@ -1217,7 +1200,7 @@ class Doku_Handler_Table {
     }
 
     function tableStart($call) {
-        $this->tableCalls[] = array('table_open',array(),$call[2]);
+        $this->tableCalls[] = array('table_open',$call[1],$call[2]);
         $this->tableCalls[] = array('tablerow_open',array(),$call[2]);
         $this->firstCell = true;
     }
@@ -1288,6 +1271,7 @@ class Doku_Handler_Table {
             // Adjust to num cols not num col delimeters
             $this->tableCalls[0][1][] = $this->maxCols - 1;
             $this->tableCalls[0][1][] = $this->maxRows;
+            $this->tableCalls[0][1][] = array_shift($this->tableCalls[0][1]);
         } else {
             trigger_error('First element in table call list is not table_open');
         }
@@ -1505,13 +1489,7 @@ class Doku_Handler_Block {
             //remove the whole paragraph
             array_splice($this->calls,$i);
         }else{
-            if ($this->calls[count($this->calls)-1][0] == 'section_edit') {
-                $tmp = array_pop($this->calls);
-                $this->calls[] = array('p_close',array(), $pos);
-                $this->calls[] = $tmp;
-            } else {
-                $this->calls[] = array('p_close',array(), $pos);
-            }
+            $this->calls[] = array('p_close',array(), $pos);
         }
 
         $this->inParagraph = false;
diff --git a/inc/parser/renderer.php b/inc/parser/renderer.php
index 65dcaf8a1..393099003 100644
--- a/inc/parser/renderer.php
+++ b/inc/parser/renderer.php
@@ -85,8 +85,6 @@ class Doku_Renderer extends DokuWiki_Plugin {
 
     function header($text, $level, $pos) {}
 
-    function section_edit($start, $end, $level, $name) {}
-
     function section_open($level) {}
 
     function section_close() {}
@@ -231,9 +229,9 @@ class Doku_Renderer extends DokuWiki_Plugin {
         $src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL
         ) {}
 
-    function table_open($maxcols = NULL, $numrows = NULL){}
+    function table_open($maxcols = NULL, $numrows = NULL, $pos){}
 
-    function table_close($begin, $end){}
+    function table_close($pos){}
 
     function tablerow_open(){}
 
diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php
index 4e848ec1d..ef62a3df9 100644
--- a/inc/parser/xhtml.php
+++ b/inc/parser/xhtml.php
@@ -29,6 +29,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     var $doc = '';        // will contain the whole document
     var $toc = array();   // will contain the Table of Contents
 
+    private $sectionedits = array(); // A stack of section edit data
 
     var $headers = array();
     var $footnotes = array();
@@ -39,6 +40,34 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     var $_counter   = array(); // used as global counter, introduced for table classes
     var $_codeblock = 0; // counts the code and file blocks, used to provide download links
 
+    /**
+     * Register a new edit section range
+     *
+     * @param $type  string The section type identifier
+     * @param $title string The section title
+     * @param $start int    The byte position for the edit start
+     * @return string A marker class for the starting HTML element
+     * @author Adrian Lang <lang@cosmocode.de>
+     */
+    protected function startSectionEdit($start, $type, $title) {
+        static $lastsecid = 0;
+        $this->sectionedits[] = array(++$lastsecid, $start, $type, $title);
+        return 'sectionedit' . $lastsecid;
+    }
+
+    /**
+     * Finish an edit section range
+     *
+     * @param $pos int The byte position for the edit end
+     * @author Adrian Lang <lang@cosmocode.de>
+     */
+    protected function finishSectionEdit($end) {
+        list($id, $start, $type, $title) = array_pop($this->sectionedits);
+        $this->doc .= "<!-- EDIT$id " . strtoupper($type) . ' "' .
+               str_replace('"', '', $title) . "\" [$start-" .
+               ($end === 0 ? '' : $end) . "] -->";
+    }
+
     function getFormat(){
         return 'xhtml';
     }
@@ -51,6 +80,17 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     }
 
     function document_end() {
+        // Finish open section edits.
+        while (count($this->sectionedits) > 0) {
+            if ($this->sectionedits[count($this->sectionedits) - 1][1] <= 1) {
+                // If there is only one section, do not write a section edit
+                // marker.
+                array_pop($this->sectionedits);
+            } else {
+                $this->finishSectionEdit(0);
+            }
+        }
+
         if ( count ($this->footnotes) > 0 ) {
             $this->doc .= '<div class="footnotes">'.DOKU_LF;
 
@@ -106,6 +146,8 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     }
 
     function header($text, $level, $pos) {
+        global $conf;
+
         if(!$text) return; //skip empty headlines
 
         $hid = $this->_headerToLink($text,true);
@@ -122,30 +164,24 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
         }
         $this->lastlevel = $level;
 
+        if ($level <= $conf['maxseclevel'] &&
+            count($this->sectionedits) > 0 &&
+            $this->sectionedits[count($this->sectionedits) - 1][2] === 'section') {
+            $this->finishSectionEdit($pos);
+        }
+
         // write the header
-        $this->doc .= DOKU_LF.'<h'.$level.'><a name="'.$hid.'" id="'.$hid.'">';
+        $this->doc .= DOKU_LF.'<h'.$level;
+        if ($level <= $conf['maxseclevel']) {
+            $this->doc .= ' class="' . $this->startSectionEdit($pos, 'section', $text) . '"';
+        }
+        $this->doc .= '><a name="'.$hid.'" id="'.$hid.'">';
         $this->doc .= $this->_xmlEntities($text);
         $this->doc .= "</a></h$level>".DOKU_LF;
     }
 
-     /**
-     * Section edit marker is replaced by an edit button when
-     * the page is editable. Replacement done in 'inc/html.php#html_secedit'
-     *
-     * @author Andreas Gohr <andi@splitbrain.org>
-     * @author Ben Coburn   <btcoburn@silicodon.net>
-     */
-    function section_edit($start, $end, $level, $name) {
-        global $conf;
-
-        if ($start!=-1 && $level<=$conf['maxseclevel']) {
-            $name = str_replace('"', '', $name);
-            $this->doc .= '<!-- SECTION "'.$name.'" ['.$start.'-'.(($end===0)?'':$end).'] -->';
-        }
-    }
-
     function section_open($level) {
-        $this->doc .= "<div class=\"level$level\">".DOKU_LF;
+        $this->doc .= "<div class='level$level'>".DOKU_LF;
     }
 
     function section_close() {
@@ -845,15 +881,16 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     }
 
     // $numrows not yet implemented
-    function table_open($maxcols = NULL, $numrows = NULL){
+    function table_open($maxcols = NULL, $numrows = NULL, $pos){
+        global $lang;
         // initialize the row counter used for classes
         $this->_counter['row_counter'] = 0;
-        $this->doc .= '<table class="inline">'.DOKU_LF;
+        $this->doc .= '<table class="inline ' . $this->startSectionEdit($pos, 'table', $lang['table_edit_title']) . '">'.DOKU_LF;
     }
 
-    function table_close($begin, $end){
+    function table_close($pos){
         $this->doc .= '</table>'.DOKU_LF;
-        $this->doc .= '<!-- TABLE ['. $begin .'-'.$end.'] -->';
+        $this->finishSectionEdit($pos);
     }
 
     function tablerow_open(){
diff --git a/lib/scripts/script.js b/lib/scripts/script.js
index b611f980a..ef4ae95a2 100644
--- a/lib/scripts/script.js
+++ b/lib/scripts/script.js
@@ -535,38 +535,24 @@ addInitEvent(function(){
  * @author Andreas Gohr <andi@splitbrain.org>
  */
 addInitEvent(function(){
-    var break_classes = new RegExp('secedit|toc|page');
     var btns = getElementsByClass('btn_secedit',document,'form');
     for(var i=0; i<btns.length; i++){
-        switch(btns[i].parentNode.className.match(/editbutton_(\w+)/)[1]) {
-        case 'plain':
-            addEvent(btns[i],'mouseover',function(e){
-                var tgt = e.target.form.parentNode;
-                do {
-                    tgt = tgt.previousSibling;
-                } while (tgt && !tgt.tagName);
-                if (!tgt) return;
-                if(tgt.nodeName != "DIV") tgt = tgt.previousSibling;
-                while(!break_classes.test(tgt.className)) {
+        addEvent(btns[i],'mouseover',function(e){
+            var tgt = e.target.form.parentNode;
+            var nr = tgt.className.match(/(\s+|^)editbutton_(\d+)(\s+|$)/)[2];
+            do {
+                tgt = tgt.previousSibling;
+            } while (tgt !== null && typeof tgt.tagName === 'undefined');
+            if (tgt === null) return;
+            while(typeof tgt.className === 'undefined' ||
+                  tgt.className.match('(\\s+|^)sectionedit' + nr + '(\\s+|$)') === null) {
+                if (typeof tgt.className !== 'undefined') {
                     tgt.className += ' section_highlight';
-                    if (tgt.tagName == 'H1') break;
-                    tgt = (tgt.previousSibling != null) ? tgt.previousSibling : tgt.parentNode;
                 }
-            });
-            break;
-
-        case 'table':
-            addEvent(btns[i],'mouseover',function(e){
-                var tgt = e.target.form.parentNode;
-                do {
-                    tgt = tgt.previousSibling;
-                } while (tgt && !tgt.tagName);
-                if (tgt && tgt.tagName === 'TABLE') {
-                    tgt.className += ' section_highlight';
-                }
-            });
-            break;
-        }
+                tgt = (tgt.previousSibling !== null) ? tgt.previousSibling : tgt.parentNode;
+            }
+            if (typeof tgt.className !== 'undefined') tgt.className += ' section_highlight';
+        });
 
         addEvent(btns[i],'mouseout',function(e){
             var secs = getElementsByClass('section_highlight');
-- 
GitLab