<?php if (!defined('PmWiki')) exit();
/*
******************************************************************************************
*                                                                                        *
*    Live Edit 2.2 - Edit parts/blocks/sections of a wiki page separately and from the   *
*                    wiki's view page without the need of going to the edit form.        *
*    Copyright (C) Dec 16, 2011  Subhrajit Bhattacharya                                  *
*                                                                                        *
*    This program is free software: you can redistribute it and/or modify                *
*    it under the terms of the GNU General Public License as published by                *
*    the Free Software Foundation, either version 3 of the License, or                   *
*    (at your option) any later version.                                                 *
*                                                                                        *
*    This program is distributed in the hope that it will be useful,                     *
*    but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                       *
*    GNU General Public License for more details <http://www.gnu.org/licenses/>.         *
*                                                                                        *
*                                                                                        *
*    Contact: subhrajit@gmail.com, http://www.subhrajit.net/                             *
*                                                                                        *
*                                                                                        *
******************************************************************************************
*/

SDV($LiveEdit->isActive, true);  // Set this to false in config.php to disable LiveEdit
SDV($LiveEdit->DefaultEnabled, false); // Whether LiveEdit will be enabled when user logs in.

SDV($LiveEdit->DefaultStyle, "Phantom_Backdrop");

SDV($LiveEdit->Markup_OpenBracket, "[:");
SDV($LiveEdit->Markup_CloseBracket, ":]");
SDV($LiveEdit->EmptyBlockContent, "Add new content here. Please change the name of the block as well.");

SDV($LiveEdit->AutoDetectStyles['BorderColor'], "cccccc");
SDV($LiveEdit->AutoDetectStyles['BorderColorHover'], "4444aa");
SDV($LiveEdit->AutoDetectStyles['Opacity'], "99");
SDV($LiveEdit->AutoDetectStyles['TitleForeColor'], "ffffff");
SDV($LiveEdit->AutoDetectStyles['DisabledTitleForeColor'], "999999");
SDV($LiveEdit->AutoDetectStyles['TitleBackColor'], "666688");
SDV($LiveEdit->AutoDetectStyles['TitleOpacity'], "80");
SDV($LiveEdit->AutoDetectStyles['SelectedBorderColor'], "ff6666");
SDV($LiveEdit->AutoDetectStyles['SelectedOpacity'], "100");

SDV($LiveEdit->MenuStyle['BackgroundColor'], "888888");
SDV($LiveEdit->MenuStyle['Opacity'], "80");
SDV($LiveEdit->MenuStyle['MenuWidth'], "250");
SDV($LiveEdit->MenuStyle['MainButtonStyle'], "font-weight:bold;color:#ffffff; cursor:pointer; cursor:hand;");
SDV($LiveEdit->MenuStyle['MenuItemsStyle'], "display:block; color:#ffffff; padding:2px 15px 2px 0px; border-top: solid 2px #aaaaaa; text-decoration:none;");
SDV($LiveEdit->MenuStyle['ShowMenuTime'], "10");
SDV($LiveEdit->MenuStyle['HideMenuTime'], "15");
        
$LiveEdit->OptionsEncodeChars = array(  array("\""    ,"&"    ,"<"   ,">"   ,"%"     ,"]"     ,"\n"  ,"\r"   ),
                                        array("\quot/","\amp/","\lt/","\gt/","\perc/","\sqnd/","\\n/","\\r/" )   );
/* ========================================================================= */


// The LiveEdit menu
$LiveEdit->MenuHTML = "";
$page = RetrieveAuthPage($pagename, 'edit', false, READPAGE_CURRENT);
if (!(!$page || !$LiveEdit->isActive))
{
    global $LiveEdit;
    $LiveEdit->MenuHTML = 
        "<div style='position:fixed;top:0px;right:0px; background-color:#".$LiveEdit->MenuStyle['BackgroundColor'].";padding:0px 3px; height:17px; opacity:0.".$LiveEdit->MenuStyle['Opacity']."; filter:alpha(opacity=".$LiveEdit->MenuStyle['Opacity'].")''>
            <script type=\"text/javascript\">
                document.LiveEditMenuShow = false;
                function ShowLiveEditMenu () {
                    var RightPos = parseInt(document.getElementById('LiveEditMenu').style.right);
                    if (RightPos<-10 && document.LiveEditMenuShow) {
                        document.getElementById('LiveEditMenu').style.right = (4+RightPos)+'px';
                        setTimeout('ShowLiveEditMenu();', ".$LiveEdit->MenuStyle['ShowMenuTime'].");
                    }
                }
                function HideLiveEditMenu () {
                    var RightPos = parseInt(document.getElementById('LiveEditMenu').style.right);
                    if (RightPos>-".$LiveEdit->MenuStyle['MenuWidth']." && !document.LiveEditMenuShow) {
                        document.getElementById('LiveEditMenu').style.right = (RightPos-4)+'px';
                        setTimeout('HideLiveEditMenu();', ".$LiveEdit->MenuStyle['HideMenuTime'].");
                    }
                }
            </script>
            <div onmouseover=\"javascript: document.LiveEditMenuShow=true; ShowLiveEditMenu(); \" onmouseout=\"javascript: document.LiveEditMenuShow=false; HideLiveEditMenu();\"><span style='".$LiveEdit->MenuStyle['MainButtonStyle']."'>LiveEdit</span>
                <div id='LiveEditMenu' style='position:fixed;top:17px;right:-".$LiveEdit->MenuStyle['MenuWidth']."px; background-color:#".$LiveEdit->MenuStyle['BackgroundColor'].";padding:0; width:".($LiveEdit->MenuStyle['MenuWidth']-10)."px; text-align:right;'>";
            if (!array_key_exists('LiveEdit', $_COOKIE))
                $_COOKIE['LiveEdit'] = (($LiveEdit->DefaultEnabled)?"true":"false");
            if ($_COOKIE['LiveEdit']=="true")
            {
                if ($_GET['action']!=="liveeditAutodetect") $LiveEdit->MenuHTML = $LiveEdit->MenuHTML .
                    "<a href='?n=".$pagename."&action=liveeditAutodetect' style='".$LiveEdit->MenuStyle['MenuItemsStyle']."'>AutoDetect blocks in this page</a>";
                else $LiveEdit->MenuHTML = $LiveEdit->MenuHTML .
                    "<a href='?n=".$pagename."' style='".$LiveEdit->MenuStyle['MenuItemsStyle']."'>Exit AutoDetect mode</a>";
    $LiveEdit->MenuHTML = $LiveEdit->MenuHTML .
                    "<a href='?n=".$pagename."&LiveEdit=ShowStyle' style='".$LiveEdit->MenuStyle['MenuItemsStyle']."'>View available styles &amp; parameters</a>
                    <a href='?n=".$pagename."&LiveEdit=false' style='".$LiveEdit->MenuStyle['MenuItemsStyle']."'>Turn Off LiveEdit!</a>";
            } else {
                $LiveEdit->MenuHTML = $LiveEdit->MenuHTML . "<a href='?n=".$pagename."&LiveEdit=true' style='".$LiveEdit->MenuStyle['MenuItemsStyle']."'>Turn On LiveEdit!</a>";
            }
        $LiveEdit->MenuHTML = $LiveEdit->MenuHTML .
                "</div>
            </div>
        </div>";
    
    SDV($HandleBrowseFmt, array(&$PageStartFmt, &$PageRedirectFmt, '$PageText', $LiveEdit->MenuHTML, &$PageEndFmt));
}
else
    setcookie('LiveEdit', (($LiveEdit->DefaultEnabled)?"true":"false"));

/* ========================================================================= */

/* This section adds an action called 'liveeditAutodetect' that helps in identifying
   and generating LiveEdit blocks automatically in a Wiki-page */

/*

Each element of $LiveEdit->AutoDetectBrackets is an array with the following elements:
   0 => Regular expression of the pattern defining the bracket
   1 => Backreference index of the bracket body (the portion to start another recursive search. -1 for no resursive search)
   2 => Backreference index of the bracket block (the one that is to be included inside the LiveEdit bracket)
   3 => Backreference index of the blanket (the portion to be blanketed before starting next cycle)
   4 => What kind of block: 'span' or 'div'
   5 => Backreference index of pre-padding content (the relevant content that comes before bracket starts - for duplication: set -1 to skip)
   6 => Backreference index of post-padding content (the relevant content that comes after bracket ends - for duplication: set -1 to skip)

If the regular expression contains ^ or $, it needs to be separate from the main pattern
        and the pattern name should start with 'Last_' or 'First_' respectively.

The order in which the patterns are defined matters. The first patterns are given more preference in
        case of conflicts.

*/

$LiveEdit->AutoDetectBrackets['TableCell'] = array( "/((\\(:(cell|head).*?:\\))(.*?))(\\n)\\(:(cell.*?|head.*?|tableend):\\)/es" , 4 , 4 , 1 , 'div', 2, 5);
$LiveEdit->AutoDetectBrackets['MarkupBlock'] = array( "/\\(:([\w]+).*?:\\)(.*?)\\(:\\1\\s*?end:\\)/es" , 2 , 0 , 0 , 'div', -1, -1);
$LiveEdit->AutoDetectBrackets['DivBlock'] = array( "/((\\n>>.+?<<)(.*?))(>>.*?<<|$)/es" , 3 , 3 , 1, 'div', 2, -1);
$LiveEdit->AutoDetectBrackets['FormattingBlocks'] = array( "/\\[(=|@)(.*?)\\1\\]/es" , 2 , 0 , 0 , 'span', -1, -1); // markup inside
$LiveEdit->AutoDetectBrackets['SingleLineMarkup'] = array( "/\\(:[\w]+.*?:\\)/e" , -1 , 0 , 0 , 'span', -1, -1); // markup inside
$LiveEdit->AutoDetectBrackets['SimpleTableCell'] = array( "/(\\|\\|(.+?))(\\|\\|)/e" , 2 , 2 , 1 , 'span', -1, 3);
$LiveEdit->AutoDetectBrackets['ListsAndIndents'] = array( "/\\n((\\*|\\*\\*|#|##|Q:|A:|->|-<|:[\w]+:)(.*?))(\\n|\\r)/es" , 3 , 3 , 1 , 'span', 2, 4);
$LiveEdit->AutoDetectBrackets['SpanBlock'] = array( "/(^|[^%])((%[^\\n%]+?%)(.*?))(%.*?%|\\|\\||\\n|$)/es" , 4 , 4 , 2 , 'span', 3, -1);
$LiveEdit->AutoDetectBrackets['Hyperlinks'] = array( "/\\[\\[([^<].*?)\\]\\]/e" , 1 , 0 , 0 , 'span', -1, -1); // markup inside
$LiveEdit->AutoDetectBrackets['Heading'] = array( "/(\\n|^)(!+(.*))/e" , 3 , 2 , 2 , 'div', -1, -1); // markup inside
$LiveEdit->AutoDetectBrackets['Paragraph'] = array( "/(\\n(\\n)(.*?))(\\n)\\n/es" , 3 , 3 , 1 , 'div', 2, 4);
$LiveEdit->AutoDetectBrackets['Last_Paragraph'] = array( "/(\\n(\\n)(.*?))\\n?$/es" , 3 , 3 , 1 , 'div', 2, 2);


// ---------------------

$LiveEdit->BlanketChar = "\235";
$LiveEdit->BlockPadding = array( 'div'=>"\n" , 'span'=>"" );
$LiveEdit->BraPosEncode = "%09d-2-%09d-%09d";
$LiveEdit->KetPosEncode = "%09d-1-%09d-%09d";
$LiveEdit->BracketPosEncode = "%09d-%01d-%09d-%09d";
$LiveEdit->PaddingEncode = "%09d+%09d";

$LiveEdit->BracketsInfo = array();
function LiveEdit_findBrackets($WikiText, $StartOffset, $Level)
{
    global $LiveEdit;
    $thisBraketInfos = array();
    
    $BlanketedWikiText = $WikiText;
    foreach ($LiveEdit->AutoDetectBrackets as $k=>$v)
    {
        $thisRegex = $v[0];
        $thisBodyBackref = $v[1];
        $thisBlockBackref = $v[2];
        $thisBlanketBackref = $v[3];
        $thisBracketType = $v[4];
        if (count($v)>5) { $thisPrepadBackref = $v[5];
        $thisPostpadBackref = $v[6]; } 
        
        if ($Level > 0 && 
            ( (preg_match("/[^\\\\]\\$/es",$thisRegex)!==0 && substr($k,0,5)==="Last_") || 
              (preg_match("/[^\\\\]\\^/es",$thisRegex)!==0 && substr($k,0,6)==="First_") )  )
            continue;
        
        $found = true;
        while ($found)
        {
            $found = false;
    
            $matchCount = preg_match($thisRegex, $BlanketedWikiText, $match, PREG_OFFSET_CAPTURE );
            if ($matchCount === 1)
            {
                $vv = $match;
                // Recursive capture inside this brackets
                if ($thisBodyBackref >= 0)
                    LiveEdit_findBrackets($vv[$thisBodyBackref][0], $StartOffset+$vv[$thisBodyBackref][1], $Level+1);
                
                $BlanketLength = strlen($vv[$thisBlanketBackref][0]);
                $BlanketedWikiText = substr_replace($BlanketedWikiText, str_repeat($LiveEdit->BlanketChar, $BlanketLength), $vv[$thisBlanketBackref][1], $BlanketLength);
        
                $thisBracketInfo->start = $StartOffset + $vv[$thisBlockBackref][1];
                $thisBracketInfo->end = $StartOffset + $vv[$thisBlockBackref][1] + strlen($vv[$thisBlockBackref][0]);
                $thisBracketInfo->blocktype = $thisBracketType;
                $thisBracketInfo->brackettype = $k;
                $thisBracketInfo->level = $Level;
                $thisBracketInfo->content = $vv[$thisBlockBackref][0];
                
                if ($thisPrepadBackref>=0) $thisBracketInfo->prepad = array($StartOffset+$vv[$thisPrepadBackref][1], strlen($vv[$thisPrepadBackref][0]));
                else $thisBracketInfo->prepad = false;
                    
                if ($thisPostpadBackref>=0) $thisBracketInfo->postpad = array($StartOffset+$vv[$thisPostpadBackref][1], strlen($vv[$thisPostpadBackref][0]));
                else $thisBracketInfo->postpad = false;
                    
                $LiveEdit->BracketsInfo[] = clone $thisBracketInfo;
                $found = true;
            }
        }
    }
    
}

# add "?action=liveeditAutodetect"
SDV($HandleActions['liveeditAutodetect'], 'HandleLiveeditAutodetect');
SDV($HandleAuth['liveeditAutodetect'], 'edit');
SDV($AuthCascade['liveeditAutodetect'], 'edit');

function HandleLiveeditAutodetect($pagename, $auth='edit') {
    global $LiveEdit, $WikiDir, $LastModFile;

    $page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
    if (!$page || $_COOKIE['LiveEdit']=="false" || !$LiveEdit->isActive) { Abort("Cannot edit $pagename<br>Possible cause: You are not logged in as an authenticated user with edit permission, or you have LiveEdit turned off. Try passing &amp;<b>LiveEdit=true</b>."); return; }

    LiveEdit_findBrackets($page['text'], 0, 0);
    $PageLength = strlen($page['text']);
    $BraKets = array();
    foreach ($LiveEdit->BracketsInfo as $k=>$v)
    {
        $id = $k;
        $thisBracketInfo = $v;
        $thisBracketInfo->enabled = true;
        
        if ( preg_match("/^\\s*$/es", $v->content) !== 0 )
            continue;
        elseif ( preg_match("/^\\s*\\Q".$LiveEdit->Markup_OpenBracket."\\E([\\w]*).*?\\Q".$LiveEdit->Markup_CloseBracket."\\E(.*?)\\Q".$LiveEdit->Markup_OpenBracket."\\E\\/\\1\\Q".$LiveEdit->Markup_CloseBracket."\\E\\s*$/es", $v->content) !== 0 )
             $thisBracketInfo->enabled = false;
        else // test for pre-brackets - may be expensive, and may not be very useful
        {
            $matches = array();
            if ($id==55) { echo substr($page['text'], 0, $thisBracketInfo->start)."------\n".substr($page['text'], $thisBracketInfo->end)."+++++\n"; 
            if( preg_match( "/\\Q".$LiveEdit->Markup_OpenBracket."\\E([\\w]*)[^\\]]*?\\Q".$LiveEdit->Markup_CloseBracket."\\E\\s*$/es", substr($page['text'], 0, $thisBracketInfo->start), $matches ) !== 0 ) { echo("matched1 ".$matches[1]."----");
                if( preg_match( "/^\\s*\\Q".$LiveEdit->Markup_OpenBracket."\\E\\/".$matches[1]."\\Q".$LiveEdit->Markup_CloseBracket."\\E/", substr($page['text'], $thisBracketInfo->end) ) !== 0 ) { echo("matched2----");
                    $thisBracketInfo->enabled = false; } } }
            
        }
         
        $thisBracketInfo->id = $id;
        $thisPadding = $LiveEdit->BlockPadding[$v->blocktype];
        $thisBracketInfo->StartPosString = sprintf($LiveEdit->BraPosEncode, $v->start, $PageLength-$v->end, $id);
        $thisBracketInfo->EndPosString = sprintf($LiveEdit->KetPosEncode, $v->end, $PageLength-$v->start, $id);
        $thisBracketInfo->PrepadInfo = ($thisBracketInfo->prepad)?sprintf($LiveEdit->PaddingEncode, $thisBracketInfo->prepad[0], $thisBracketInfo->prepad[1]):"";
        $thisBracketInfo->PostpadInfo = ($thisBracketInfo->postpad)?sprintf($LiveEdit->PaddingEncode, $thisBracketInfo->postpad[0], $thisBracketInfo->postpad[1]):"";
        $BraKets[$thisBracketInfo->StartPosString] = $thisPadding.Keep(LiveEdit_GenerateBra($thisBracketInfo)).$thisPadding;
        $BraKets[$thisBracketInfo->EndPosString] = $thisPadding.Keep(LiveEdit_GenerateKet($thisBracketInfo)).$thisPadding;
    }
    ksort($BraKets);
    //echo(implode("\n",array_keys($BraKets)));

    $TheWikiText = "";
    $startPos = 0;
    foreach ($BraKets as $k=>$v)
    {
        list($endPos, $dummy, $dummy, $dummy) = sscanf($k, $LiveEdit->BracketPosEncode);
        $TheWikiText = $TheWikiText . substr($page['text'], $startPos, $endPos-$startPos) . $BraKets[$k];
        //echo ($k." (".$endPos."): ".MarkupToHTML($pagename, $BraKets[$k])."\n");
        //echo (substr($page['text'], $startPos, $endPos-$startPos) . " [".$k."] ");
        $startPos = $endPos;
    }
    $TheWikiText = $TheWikiText . substr($page['text'], $startPos);

    $MainBracketInfo->id = 'main';
    $MainBracketInfo->blocktype = 'div';
    $MainBracketInfo->brackettype = 'FullPage';
    $MainBracketInfo->enabled = true;
    if ( preg_match("/^\\s*\\Q".$LiveEdit->Markup_OpenBracket."\\E([\\w]*).*?\\Q".$LiveEdit->Markup_CloseBracket."\\E(.*?)\\Q".$LiveEdit->Markup_OpenBracket."\\E\\/\\1\\Q".$LiveEdit->Markup_CloseBracket."\\E\\s*$/es", $TheWikiText) )
    $MainBracketInfo->enabled = false;

    $TheWikiText = "\n".Keep(LiveEdit_GenerateBra($MainBracketInfo))."\n" . $TheWikiText . "\n".Keep(LiveEdit_GenerateKet($MainBracketInfo))."\n";

    //echo $TheWikiText;
    $TheWikiText = Keep("<form method=POST action=\"?n=".$pagename."&action=liveeditCreateblocks\" >"). $TheWikiText .
                   Keep( "<input type='hidden' name='LiveEditPageHash' value='".md5($page['text'])."' />".
                         "<input type='hidden' name='basetime' value='".time()."'>".
                         "<input type='submit' value='Create Selected Blocks' />".
                         "</form>");
    $TheHTML = MarkupToHTML($pagename, $TheWikiText);

    global $HandleBrowseFmt, $PageStartFmt, $PageRedirectFmt, $PageEndFmt;
    $HandleBrowseFmt = array(&$PageStartFmt, &$PageRedirectFmt, $TheHTML, $LiveEdit->MenuHTML, &$PageEndFmt);
    PrintFmt($pagename,$HandleBrowseFmt);
}


function LiveEdit_GenerateBra($info)
{
    global $LiveEdit;
    
    $tagName = $info->blocktype;
    $id = $info->id;
    $OutHTML = "<".$tagName." id=\"LiveEditAutoBlock_".$id."\" style='border: solid 1px #".$LiveEdit->AutoDetectStyles['BorderColor']."; margin:5px;padding:0; position:relative; opacity:0.".$LiveEdit->AutoDetectStyles['Opacity']."; filter:alpha(opacity=".$LiveEdit->AutoDetectStyles['Opacity'].")' ".
                         " onmouseover = \"javascript: document.getElementById('LiveEditAutoBlockForm_".$id."').style.display = 'block'; 
                                             if (!document.getElementById('LiveEditAutoBlockCheckbox_".$id."').checked)
                                                 document.getElementById('LiveEditAutoBlock_".$id."').style.borderColor='#".$LiveEdit->AutoDetectStyles['BorderColorHover']."'; \" ".
                         " onmouseout = \"javascript: document.getElementById('LiveEditAutoBlockForm_".$id."').style.display = 'none'; 
                                             if (!document.getElementById('LiveEditAutoBlockCheckbox_".$id."').checked)
                                                 document.getElementById('LiveEditAutoBlock_".$id."').style.borderColor='#".$LiveEdit->AutoDetectStyles['BorderColor']."'; \" ".
                         ">".
                  "<span id=\"LiveEditAutoBlockForm_".$id."\" style='width:20em; background-color:#".$LiveEdit->AutoDetectStyles['TitleBackColor']."; padding-right:0; margin:0;".
                           " display:none; position:absolute; left:0; top:0; z-index:99997; opacity:0.".$LiveEdit->AutoDetectStyles['TitleOpacity']."; filter:alpha(opacity=".$LiveEdit->AutoDetectStyles['TitleOpacity'].")'>".
                     "<input type='checkbox' id=\"LiveEditAutoBlockCheckbox_".$id."\" name='LiveEditAutoBlock[]' ".
                            ($info->enabled?"":"checked disabled").
                            " value='".sprintf("%d,%d,%d,%s,%s,%s,%s,%s",$id,$info->start,$info->end,$info->StartPosString,$info->EndPosString,$info->blocktype,$info->PrepadInfo,$info->PostpadInfo)."'".
                           " onClick=\"javascript: if (this.checked) ".
                           "           { document.getElementById('LiveEditAutoBlock_".$id."').style.borderColor='#".$LiveEdit->AutoDetectStyles['SelectedBorderColor']."'; ".
                           "             document.getElementById('LiveEditAutoBlock_".$id."').style.opacity=".$LiveEdit->AutoDetectStyles['SelectedOpacity']."/100; ".
                           "             document.getElementById('LiveEditAutoBlock_".$id."').style.filter='alpha(opacity=".$LiveEdit->AutoDetectStyles['SelectedOpacity'].")'; }  ".
                           "      else { document.getElementById('LiveEditAutoBlock_".$id."').style.borderColor='#".$LiveEdit->AutoDetectStyles['BorderColor']."'; ".
                           "             document.getElementById('LiveEditAutoBlock_".$id."').style.opacity=".$LiveEdit->AutoDetectStyles['Opacity']."/100; ".
                           "             document.getElementById('LiveEditAutoBlock_".$id."').style.filter='alpha(opacity=".$LiveEdit->AutoDetectStyles['Opacity'].")'; } \" ".
                     "/>".
                     "<span style='color:#".($info->enabled?$LiveEdit->AutoDetectStyles['TitleForeColor']:$LiveEdit->AutoDetectStyles['DisabledTitleForeColor']).";'> Select (".$info->brackettype.")</span>".
                  "</span>";
    return $OutHTML;
}

function LiveEdit_GenerateKet($info)
{
    $tagName = $info->blocktype;
    return "</".$tagName.">"; //."-".$info->id."-";
}

// ----------------------------------------------

/* This section adds an action called 'liveeditCreateblocks' to processes the request submitted by liveeditAutodetect */

# add "?action=liveeditCreateblocks"
SDV($HandleActions['liveeditCreateblocks'], 'HandleLiveeditCreateblocks');
SDV($HandleAuth['liveeditCreateblocks'], 'edit');
SDV($AuthCascade['liveeditCreateblocks'], 'edit');

function HandleLiveeditCreateblocks($pagename, $auth='edit') {
  global $LiveEdit, $SaveProperties, $EnablePost;
  
  $page = RetrieveAuthPage($pagename, $auth, true, 0);
  if (!$page || $_COOKIE['LiveEdit']=="false" || !$LiveEdit->isActive) { Abort("Cannot edit $pagename"); return; }
  if (md5($page['text']) !== $_POST['LiveEditPageHash']) 
      { Abort("Edit conflict! The content of $pagename has been changed. Please try again!"); return; }
  $newpage = $page;

  if (!empty($_POST['LiveEditAutoBlock']))
  {
     foreach ($_POST['LiveEditAutoBlock'] as $k=>$v)
     {
        $infos = explode(",",$v);
        $id = $infos[0];
        $start = $infos[1];
        $end = $infos[2];
        $StartPosString = $infos[3];
        $EndPosString = $infos[4];
        $blocktype = $infos[5];
        switch ($blocktype) {
           case "div":
              $optstr = " ".$LiveEdit->DefaultStyle;
              break;
           case "span":
              $optstr = " ".$LiveEdit->DefaultStyle."_Inline";
              break;
        }
        $prepadinfo = $infos[6];
        if (!empty($prepadinfo))
        {
            $prepadsubstr = explode("+",$prepadinfo);
            $optstr .= " LEABprepad=\"" . LiveEditOptionValueEncode(substr($page['text'], intval($prepadsubstr[0]), intval($prepadsubstr[1])))."\"";
        }
        $postpadinfo = $infos[7];
        if (!empty($postpadinfo))
        {
            $postpadsubstr = explode("+",$postpadinfo);
            $optstr .= " LEABpostpad=\"" . LiveEditOptionValueEncode(substr($page['text'], intval($postpadsubstr[0]), intval($postpadsubstr[1])))."\"";
        }
        $blockname = "LEAB_".$k."_".$id."_".$start."_".$end; // LiveEdit Auto Block
        $inserts[$StartPosString] = $LiveEdit->Markup_OpenBracket.$blockname.$optstr.$LiveEdit->Markup_CloseBracket;
        $inserts[$EndPosString] = $LiveEdit->Markup_OpenBracket."/".$blockname.$LiveEdit->Markup_CloseBracket;
     }
     
     ksort($inserts);
  
     $TheWikiText = "";
     $startPos = 0;
     foreach ($inserts as $k=>$v)
     {
        list($endPos, $dummy, $dummy, $dummy) = sscanf($k, $LiveEdit->BracketPosEncode);
        $TheWikiText = $TheWikiText . substr($page['text'], $startPos, $endPos-$startPos) . $inserts[$k];
        $startPos = $endPos;
     }
     $TheWikiText = $TheWikiText . substr($page['text'], $startPos);
     
     $newpage['text'] = $TheWikiText;
     
     $newpage['csum'] = "Created LiveEdit block $blockname using Autodetect";
     $newpage['action'] = "edit";
     $newpage['n'] = $pagename;
     $newpage['time'] = time();
     $newpage['basetime'] = $_POST['basetime'];
     $EnablePost = true;
     foreach((array)$SaveProperties as $k)
        SetProperty($pagename, $k, $page[$k]);
     PCache($pagename, $newpage);
     UpdatePage($pagename, $page, $newpage);
  }
  
  Redirect($pagename);
  exit;
}


/* ========================================================================= */
/* ========================================================================= */

/* This section adds an action called 'liveeditSave' and processes the submitted form */

# add "?action=liveeditSave"
SDV($HandleActions['liveeditSave'], 'HandleLiveeditSave');
SDV($HandleAuth['liveeditSave'], 'edit');
SDV($AuthCascade['liveeditSave'], 'edit');

function HandleLiveeditSave($pagename, $auth='edit') {
  global $WikiDir, $LastModFile, $LiveEdit, $EnablePost, $SaveProperties;
  
  $page = RetrieveAuthPage($pagename, $auth, true, 0);
  if (!$page) { Abort("Cannot edit $pagename"); return; }
  $newpage = $page;
  
  $blockname = $_GET['liveeditBlock'];
  $newBlockName = $blockname;
  if ( !$_POST['cancel'] )
  {
      // Extract the values from the mandetory (hidden) fields
      $OriginalFullBlockHash = rawurldecode($_POST['LiveEditOriginalHash_'.$blockname]);
      $OriginalStart = rawurldecode($_POST['LiveEditOriginalStart_'.$blockname]);
      $OriginalEnd = rawurldecode($_POST['LiveEditOriginalEnd_'.$blockname]);
      
      // Find/extract the content
      $startPos = strpos($page['text'], $OriginalStart);
      $startPosPos = $startPos+strlen($OriginalStart);
      $startPos2 = strpos($page['text'], $OriginalStart, $startPosPos);
      if ($startPos2 !== false) { Abort("!!! Cannot edit block <b>$blockname</b>. Possible cause: Multiple blocks with same name."); return; }
      $endPos = strpos($page['text'], $OriginalEnd, $startPosPos);
      $endPosPos = $endPos+strlen($OriginalEnd);
      
      $rawWikitext = substr($page['text'], $startPosPos, $endPos-$startPosPos);
      $OriginalFullBlock = substr($page['text'], $startPos, $endPosPos-$startPos);
      if ($OriginalFullBlockHash != md5($OriginalFullBlock) || 
              @strpos( $page['text'], $OriginalFullBlock,
                              strpos($page['text'],$OriginalFullBlock)+strlen($OriginalFullBlock) ) != false )
         { Abort("!!! Cannot edit block <b>$blockname</b>. Possible cause: Ambiguous block."); return; }
      
      // Extract options
      if ( array_key_exists('LiveEditOptions_'.$blockname,$_POST) )
          $optstr = $_POST['LiveEditOptions_'.$blockname];
      else
          $optstr = "";
      list($StyleName, $params) = ParseLiveEditOptionString($optstr);
      $newoptstr = $StyleName;
      foreach ($params as $pp=>$vv)
        $newoptstr .= " ".$pp."=\"".LiveEditOptionValueEncode($vv)."\"";
      
      
      // The changed wiki-text
      if ($_POST['LiveEdit_'.$blockname])
         $ChangedWikiText = $_POST['LiveEdit_'.$blockname];
      else
         $ChangedWikiText = $rawWikitext;
         
      // The changed start and end strings
      if ($_POST['remove'] || $_POST['delete'])
      {
        $ChangedStart = "";
        $ChangedEnd = "";
        if ($_POST['delete'])
            $ChangedWikiText = "";
      }
      elseif (array_key_exists('LiveEditBlockName_'.$blockname,$_POST))
      {
         $newBlockName = $_POST['LiveEditBlockName_'.$blockname];
         $ChangedStart = $LiveEdit->Markup_OpenBracket . $newBlockName . " " . $newoptstr . $LiveEdit->Markup_CloseBracket;
         $ChangedEnd = $LiveEdit->Markup_OpenBracket."/".$newBlockName.$LiveEdit->Markup_CloseBracket;
      }
      else
      {
         $ChangedStart = $OriginalStart;
         $ChangedEnd = $OriginalEnd;
      }
      
      $ChangedFullBlock = $ChangedStart.$ChangedWikiText.$ChangedEnd;
      
      if ($_POST['addbefore'] || $_POST['addafter'])
      {
          $NewNewBlockname = $newBlockName . "_".time()."x".rand(1,999);
          $ChangedStartNew = $LiveEdit->Markup_OpenBracket . $NewNewBlockname . " " . $newoptstr . $LiveEdit->Markup_CloseBracket;
          $ChangedEndNew = $LiveEdit->Markup_OpenBracket."/".$NewNewBlockname.$LiveEdit->Markup_CloseBracket;
          
          $prepad = "";
          if (array_key_exists('LEABprepad',$params)) $prepad = LiveEditOptionValueDecode($params['LEABprepad']);
          $postpad = "";
          if (array_key_exists('LEABpostpad',$params)) $postpad = LiveEditOptionValueDecode($params['LEABpostpad']);
          
          if ($_POST['addbefore'])
            $ChangedFullBlock = $ChangedStartNew . $LiveEdit->EmptyBlockContent . $ChangedEndNew .$postpad.$prepad. $ChangedFullBlock;
          elseif ($_POST['addafter'])
            $ChangedFullBlock = $ChangedFullBlock .$postpad.$prepad. $ChangedStartNew . $LiveEdit->EmptyBlockContent . $ChangedEndNew;
      }
      
      if ($_POST['copybefore'] || $_POST['copyafter'])
      {
          $NewNewBlockname = $newBlockName . "_".time()."x".rand(1,999);
          $ChangedStartNew = $LiveEdit->Markup_OpenBracket . $NewNewBlockname . " " . $newoptstr . $LiveEdit->Markup_CloseBracket;
          $ChangedEndNew = $LiveEdit->Markup_OpenBracket."/".$NewNewBlockname.$LiveEdit->Markup_CloseBracket;
          
          $prepad = "";
          if (array_key_exists('LEABprepad',$params)) $prepad = LiveEditOptionValueDecode($params['LEABprepad']);
          $postpad = "";
          if (array_key_exists('LEABpostpad',$params)) $postpad = LiveEditOptionValueDecode($params['LEABpostpad']);
          
          if ($_POST['copybefore'])
            $ChangedFullBlock = $ChangedStartNew . $ChangedWikiText . $ChangedEndNew .$postpad.$prepad. $ChangedFullBlock;
          elseif ($_POST['copyafter'])
            $ChangedFullBlock = $ChangedFullBlock .$postpad.$prepad. $ChangedStartNew . $ChangedWikiText . $ChangedEndNew;
      }
      
      $newpage['text'] = str_replace($OriginalFullBlock, $ChangedFullBlock, $newpage['text']);
      $newpage['text'] = str_replace("\r", '', stripmagic($newpage['text']));   // This removes the unwanted \r added in textarea
      
      $newpage['csum'] = "Updated LiveEdit block $blockname";
      $newpage['action'] = "edit";
      $newpage['n'] = $pagename;
      $newpage['time'] = time();
      $newpage['basetime'] = $_POST['basetime'];
      $EnablePost = true;
      foreach((array)$SaveProperties as $k)
        SetProperty($pagename, $k, $page[$k]);
      PCache($pagename, $newpage);
      UpdatePage($pagename, $page, $newpage);
  }

  Redirect($pagename."#".$newBlockName."_anchor");
  exit;
}

/* ========================================================================= */

/* This section generates the main LiveEdit form, and corresponding HTML+Javascripts */

// Start of the markup:
//    [:BlockName:] ...
//    [:BlockName StyleName:] ...
//    [:BlockName StyleGroup.StylePage:] ...
//    [:... ... param1="..." param2="..." ...:] ... (NOTE: param value needs to be in double quote and cannot contain the characters '"' and ':]' )
// End of the markup:
//    ... [:/BlockName:]

// [:BlockName:] ... [:/BlockName:]
Markup('liveeditblock', '<_begin',
        "/(\\Q".$LiveEdit->Markup_OpenBracket."\\E([\\w]*)\\Q".$LiveEdit->Markup_CloseBracket."\\E)(.*?)(\\Q".$LiveEdit->Markup_OpenBracket."\\E\\/\\2\\Q".$LiveEdit->Markup_CloseBracket."\\E)/es",
        "GenerateLiveEditBlock(\$pagename,PSS('\$2'),PSS('\$3'),PSS(''),PSS('\$1'),PSS('\$4'))");
// [:BlockName options:] ... [:/BlockName:]
Markup('liveeditblock2', '<_begin',
       "/(\\Q".$LiveEdit->Markup_OpenBracket."\\E([\\w]*)\\s+(.*?)\\Q".$LiveEdit->Markup_CloseBracket."\\E)(.*?)(\\Q".$LiveEdit->Markup_OpenBracket."\\E\\/\\2\\Q".$LiveEdit->Markup_CloseBracket."\\E)/es",
        "GenerateLiveEditBlock(\$pagename,PSS('\$2'),PSS('\$4'),PSS('\$3'),PSS('\$1'),PSS('\$5'))");

// Support for older version (TODO: remove this in future version)
// [#-BlockName] ... [-#]
Markup('liveeditblock_old', '<_begin', "/(\\[#-([\\w]*)\\])(.*?)(\\[-#\\])/es",
        "GenerateLiveEditBlock(\$pagename,PSS('\$2'),PSS('\$3'),PSS(''),PSS('\$1'),PSS('\$4'))");
// [#-BlockName options] ... [-#]
Markup('liveeditblock_old2', '<_begin', "/(\\[#-([\\w]*)\\s+(.*?)\\])(.*?)(\\[-#\\])/es",
        "GenerateLiveEditBlock(\$pagename,PSS('\$2'),PSS('\$4'),PSS('\$3'),PSS('\$1'),PSS('\$5'))");
        
        

function ParseLiveEditOptionString($optstr)
{
     // Get StyleName
    preg_match("/^([-\\w.]*)(\\s+[^=\\s]+|\\s*$)/", $optstr, $StyleNameMatch);
    if (!empty($StyleNameMatch))
        $StyleName = $StyleNameMatch[1];
    else
        $StyleName = $LiveEdit->DefaultStyle;
      
    // Get Parameters
    preg_match_all("/([\\w]+)\\s*=\\s*\"(.*?)\"/", $optstr, $ParamsMatch, PREG_SET_ORDER);
    $params = array();
    foreach ($ParamsMatch as $ParamsJoint)
        $params[$ParamsJoint[1]] = LiveEditOptionValueDecode($ParamsJoint[2]);
        
    return array($StyleName, $params);
}


function GenerateLiveEditBlock($pagename, $blockname, $wikitext, $options, $start, $end)
{
   global $LiveEdit;
   
   $page = RetrieveAuthPage($pagename, 'edit', false, READPAGE_CURRENT);
   if ( !$page || $_COOKIE['LiveEdit']=="false" || !$LiveEdit->isActive || $_GET['action']=="liveeditAutodetect" )
      { PRR(); return $wikitext; }
   
   $retHTML = "";

   $startPos = strpos($page['text'], $start);
   $startPosPos = $startPos+strlen($start);
   $startPos2 = strpos($page['text'], $start, $startPosPos);
   if ($startPos2 !== false)
      return $wikitext;
   $endPos = strpos($page['text'], $end, $startPosPos);
   $endPosPos = $endPos+strlen($end);
   
   $rawWikitext = substr($page['text'], $startPosPos, $endPos-$startPosPos);
   $rawBlockContent = substr($page['text'], $startPos, $endPosPos-$startPos);
   
   list($StyleName, $params) = ParseLiveEditOptionString($options);
   $HTMLarray = LiveEditHTMLfromTemplate($StyleName, $pagename, $blockname, $rawWikitext, $params, $options, md5($rawBlockContent), $start, $end);
   
   if (preg_match("/Inline$/es", $StyleName) || preg_match("/_inline$/esi", $StyleName))
       $sep = "";
   else
       $sep = "\n";
       
   if (count($HTMLarray)==2)
   {
       PRR();
       return $sep.Keep($HTMLarray[0]).$sep.$wikitext.$sep.Keep($HTMLarray[1]).$sep;
   }
   else
       return Keep($HTMLarray[0]);
}

/* ========================================================================= */

/* LiveEdit template functions */

$LiveEdit->TemplatePlaceholders["FormAction"] = "?n={\$pagename}&action=liveeditSave&liveeditBlock={\$blockname}";
$LiveEdit->TemplatePlaceholders["FormElements"] = 
    "<span style=\"visibility:hidden; display:none; \">".
        "<input type='hidden' name='LiveEditOriginalHash_{\$blockname}' value=\"{\$LiveEdit->BlockHash}\">".
        "<input type='hidden' name='LiveEditOriginalStart_{\$blockname}' value=\"{\$LiveEdit->BlockStart}\">".
        "<input type='hidden' name='LiveEditOriginalEnd_{\$blockname}' value=\"{\$LiveEdit->BlockEnd}\">".
        "<input type='hidden' name='basetime' value='".time()."'>".
    "</span>";
$LiveEdit->TemplatePlaceholders["FormSaveButtonName"] = "save";
$LiveEdit->TemplatePlaceholders["FormCancelButtonName"] = "cancel";
$LiveEdit->TemplatePlaceholders["FormRemoveButtonName"] = "remove";
$LiveEdit->TemplatePlaceholders["FormDeleteButtonName"] = "delete";
$LiveEdit->TemplatePlaceholders["FormAddBeforeButtonName"] = "addbefore";
$LiveEdit->TemplatePlaceholders["FormAddAfterButtonName"] = "addafter";
$LiveEdit->TemplatePlaceholders["FormCopyBeforeButtonName"] = "copybefore";
$LiveEdit->TemplatePlaceholders["FormCopyAfterButtonName"] = "copyafter";

function LiveEditHTMLfromTemplate($StyleName, $pagename, $blockname, $wikitext, $inParams, $optionString, $FullBlockHash, $BlockStart, $BlockEnd)
{
    global $LiveEdit;
    
    if (!empty($StyleName) && ($stylepage=RetrieveAuthPage($StyleName, 'read', false, READPAGE_CURRENT)) && !empty($stylepage['text'])) 
        $HTML = $stylepage['text'];
    else
        $HTML = GetLiveEditStyleHTML($StyleName);
    
    // Substitute the paramater values (parameter values themselves can contain the standard placeholders)
    if (!empty($inParams)) // First substitute the input parameters
        foreach ($inParams as $k=>$v)
            $HTML = preg_replace("/{\\\$params:".$k."=?[^}]*?}/", $v, $HTML);
    $HTML = preg_replace("/{\\\$params:[\w]+=\\s*\"([^}\"]*?)\"\\s*}/", "\$1", $HTML); // Among the remaining, use default values
        
    // Substitute the mandetory placeholders
    foreach ($LiveEdit->TemplatePlaceholders as $k=>$v) {
        $HTML = str_replace("{\$LiveEdit->".$k."}", $v, $HTML, $count);
        if ($count==0)
            return array("<pre> <b>LiveEdit:</b> Error in template ".$StyleName.
                         ": placeholder <b>{\$LiveEdit->".$k."}</b> not found.\n\n $HTML</pre>", "");
    }
    
    // Substitute the standard variables
    $HTML = str_replace("{\$pagename}", $pagename, $HTML);
    $HTML = str_replace("{\$blockname}", $blockname, $HTML);
    
    // Form elements: Complete block content, start and end pos of wiki text
    $HTML = str_replace("{\$LiveEdit->BlockHash}", rawurlencode($FullBlockHash), $HTML);
    $HTML = str_replace("{\$LiveEdit->BlockStart}", rawurlencode($BlockStart), $HTML);
    $HTML = str_replace("{\$LiveEdit->BlockEnd}", rawurlencode($BlockEnd), $HTML);
    
    // Wiki text for displaying inside textarea
    // HTML text area does not display the first linebreak, if there is one. So fix that!
    $firstChar = substr($wikitext, 0, 1);
    if( $firstChar == "\n" || $firstChar == "\r" )
       $wikitext = $firstChar.$wikitext;
    $HTML = str_replace("{\$LiveEdit->WikiTextExtract}", htmlspecialchars($wikitext), $HTML);
    $HTML = str_replace("{\$LiveEdit->OptionsString}", htmlspecialchars($optionString), $HTML);
    
    // Split at the DisplayTextPlaceholder
    $HTML = explode("{\$LiveEdit->DisplayTextPlaceholder}", $HTML);
    
    return $HTML;
}

/* ========================================================================= */

// TODO: Edit and add to the following

/* ========================================================================= */
/* ------------------ LiveEdit templates and styles ------------------------ */
/* ========================================================================= */

/*
Note: If you create your own template at Group.TemplatePage
      you will need to include the following placeholders

Mandetory placeholders:
      {$LiveEdit->FormAction}
      {$LiveEdit->FormElements}
      {$LiveEdit->FormSaveButtonName}
      {$LiveEdit->FormCancelButtonName}
      {$LiveEdit->FormRemoveButtonName}
      {$LiveEdit->FormDeleteButtonName}
      {$LiveEdit->FormAddBeforeButtonName}
      {$LiveEdit->FormAddAfterButtonName}
Optional Placeholders:
      {$LiveEdit->DisplayTextPlaceholder}
      {$LiveEdit->WikiTextExtract}
      {$LiveEdit->OptionsString}
Optional variables:
      {$blockname}
      {$pagename}
      {$params:<ParamName>=<ParamDefaultValue>}
Suggested parameters:
      {$params:DisplayType=<block|inline-block>}
HTML items (all optional)
      {$blockname}_anchor
Input field names (all optional):
      LiveEdit_{$blockname}
      LiveEditOptions_{$blockname}
      LiveEditBlockName_{$blockname}
*/

/* ========================================================================= */
// The sub-templates
// Format:
//     $LiveEdit->SubTemplates['Groupname']['Templatename']
//     Note: 'Templatename' must 
//                  i. be unique, even across different Groupnames,
//                 ii. start with an upper-case letter, and rest be lower case

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

// Form sub-templates


$LiveEdit->SubTemplates['Form']['Popup'] =
       "<div class='LiveEdit-formdiv' id=\"{\$blockname}_divblock\" style=\"{\$params:FormDivStyle=\"border:solid 1px #888888; left:-1px; top:1.5em; background-color:#eeeeee; width:600px; margin:0px; padding:0px;\"} position:absolute; display:none; z-index:99998; \">".
       // Beginning of form
       "<form method=POST action=\"{\$LiveEdit->FormAction}\" onsubmit='return validateLiveEditForm(this);' >".
       "{\$LiveEdit->FormElements}".
       // Form title
       "<div class='LiveEdit-formtitle' style=\"{\$params:FormTitleStyle=\"margin:10px;\"}\">".
       // The close button
       "<a href='javascript:void(0);' style='display:inline; {\$params:FormCloseButtonStyle=\"background-color:#888888;border:solid 1px #222222;font-size:1.5em;font-weight:bold;padding:3px 5px;margin:2px;color:#880000;\"} float:right;' onclick=\"javascript: ".
                     " document.getElementById('{\$blockname}_divblock').style.display = 'none'; " .
                     " document.LiveEdit_FormOpened = false; " .
                     " if (document.getElementById('{\$blockname}_editlink')) { document.getElementById('{\$blockname}_editlink').innerHTML = 'edit';} ".
       " \">X</a> ".
       // The heading
       "Editing block <input value=\"{\$blockname}\" style=\"{\$params:FormBlocknameInputStyle=\"border:solid 1px #888888;background-color:#eeeeee;font-weight:bold;\"}\" name='LiveEditBlockName_{\$blockname}' /> ".
       "</div>".
       // The options inputbox
       "<span style='margin-left:10px;margin-top:0px;'>options <a id='{\$blockname}_optionslink' href='javascript:void(0);' onclick=\"javascript: ".
                     " if (document.getElementById('{\$blockname}_optionsblock').style.display == 'none') { " .
                     "      document.getElementById('{\$blockname}_optionsblock').style.display = 'block'; 
                            document.getElementById('{\$blockname}_optionsquickref').style.display = 'inline';  " .
                     "      document.getElementById('{\$blockname}_optionslink').innerHTML = '[ - ]';  " .
                     " } else { " .
                     "      document.getElementById('{\$blockname}_optionsblock').style.display = 'none'; 
                            document.getElementById('{\$blockname}_optionsquickref').style.display = 'none';  " .
                     "      document.getElementById('{\$blockname}_optionslink').innerHTML = '[+]';  } ".
       "\" >[+]</a></span> <span id='{\$blockname}_optionsquickref' style='margin-left:10px;margin-top:0px;display:none;'>[ <a target='_blank' href='?LiveEdit=ShowStyle'>View available styles and parameters</a> ]</span>".
       "<div class='LiveEdit-optionsareadiv' id=\"{\$blockname}_optionsblock\" style=\"display:none; {\$params:FormOptionareaStyle=\"margin:10px;\"}\" ><textarea class='LiveEdit-optionsarea' name='LiveEditOptions_{\$blockname}' rows='2'>{\$LiveEdit->OptionsString}</textarea></div>".
       // The main textarea
       "<div class='LiveEdit-textareadiv' style=\"{\$params:FormTextareaStyle=\"margin:10px;\"}\"><textarea class='LiveEdit-textarea' name='LiveEdit_{\$blockname}' rows='{\$params:FormTextBoxRowCount=\"15\"} '>{\$LiveEdit->WikiTextExtract}</textarea></div>".
       // The buttons
       "<div class='LiveEdit-buttondiv' style=\"{\$params:FormButtonsStyle=\"margin:10px;\"}\">".
       "<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormSaveButtonName}' value='Save this block'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormCancelButtonName}' value='Cancel'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormDeleteButtonName}' value='Delete block'>".
       "&nbsp;&nbsp;&nbsp;&nbsp;[<a href='?n=Site.EditQuickReference' target='_blank'>Quick Reference</a>]".
       "<hr style='height:1px;border:none;background-color:#666;margin:5px;'/>".
       "<table border=0 cellpadding=0 cellspacing=0><tr><td><span style='font-weight:bold;font-size:1.1em;'>Save and...&nbsp;&nbsp;</span></td><td>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormAddBeforeButtonName}' value='Add block before'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormAddAfterButtonName}' value='Add block after'><br/>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormCopyBeforeButtonName}' value='Copy block before'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormCopyAfterButtonName}' value='Copy block after'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormRemoveButtonName}' value='Remove block brackets'>".
       "</td></tr></table></div>".
       // End of form
       "</form></div>";

// -----------------------------------------------------------------

$LiveEdit->SubTemplates['Form']['Backdrop'] =
       "<center><div id=\"{\$blockname}_divblock\" style='position:fixed;z-index=99999;top:0;left:0;margin:0;padding:0; display:none;'>".
       // Start of form
       "<form method=POST action=\"{\$LiveEdit->FormAction}\" onsubmit='return validateLiveEditForm(this);'>".
       "{\$LiveEdit->FormElements}".
       // the backdrop
       "<div style='position:fixed; left:0px; top:0px; z-index:100000; width:80000px;height:80000px; {\$params:FormBackdropStyle=\"background-color:#444444; opacity:0.75; filter:'alpha(opacity=75)';\"}'></div>".
       // Form content and title
       "<div style='position:fixed; left:0px; top:0px; width:100%; height:100%;'>".
       "<div class='LiveEdit-formdiv' style=\"position:relative; {\$params:FormDivStyle=\"border:solid 1px #888888; background-color:#222222; width:600px; padding:10px;\"} margin-top:{\$params:FormTopSpace=\"100px\"}; margin-left:auto; margin-right:auto; z-index:100001;\">".
       "<div class='LiveEdit-formtitle' style=\"{\$params:FormTitleStyle=\"margin:10px; color:#ffffff;\"}\">".
       // The close button
       "<a href='javascript:void(0);' style='display:inline;position:absolute; {\$params:FormClosebuttonStyle=\"background-color:#bbbbbb;color:#aa0022;border:solid 2px #888888;font-size:1.5em;font-weight:bold;padding:1px 2px;margin:2px; left:25px;top:15px;\"}' onclick=\"javascript: ".
                     " document.getElementById('{\$blockname}_divblock').style.display = 'none'; " .
                     " setTimeout('document.LiveEdit_FormOpened = false;', 500); " .
                     " if (document.getElementById('{\$blockname}_editlink')) { document.getElementById('{\$blockname}_editlink').innerHTML = 'edit';} ".
       " \">X</a> ".
       // The heading
       "Editing block <input value=\"{\$blockname}\" style=\"{\$params:FormBlocknameInputStyle=\"border:solid 1px #aaaaaa;background-color:#222222;font-weight:bold;color:#ffffff;\"}\" name='LiveEditBlockName_{\$blockname}' /> ".
       "</div>".
       // The main textarea
       "<div class='LiveEdit-textareadiv' style=\"{\$params:FormTextareaStyle=\"margin:10px;\"}\"><textarea class='LiveEdit-textarea' name='LiveEdit_{\$blockname}' rows='{\$params:FormTextBoxRowCount=\"15\"} ' style='background-color:#dddddd;'>{\$LiveEdit->WikiTextExtract}</textarea></div>".
       // The options textbox
       "<span style='margin-left:10px;margin-top:0px;color:#ffffff;position:relative;left:-260px;'>options <a id='{\$blockname}_optionslink' href='javascript:void(0);' onclick=\"javascript: ".
                     " if (document.getElementById('{\$blockname}_optionsblock').style.display == 'none') { " .
                     "      document.getElementById('{\$blockname}_optionsblock').style.display = 'block'; 
                            document.getElementById('{\$blockname}_optionsquickref').style.display = 'inline'; " .
                     "      document.getElementById('{\$blockname}_optionslink').innerHTML = '[ - ]';  " .
                     " } else { " .
                     "      document.getElementById('{\$blockname}_optionsblock').style.display = 'none'; 
                            document.getElementById('{\$blockname}_optionsquickref').style.display = 'none'; " .
                     "      document.getElementById('{\$blockname}_optionslink').innerHTML = '[+]';  } ".
       "\" >[+]</a>  <span id='{\$blockname}_optionsquickref' style='margin-left:10px;margin-top:0px;display:none;position:absolute; left:70px;top:0px; white-space:nowrap;'>[ <a target='_blank' href='?LiveEdit=ShowStyle'>View available styles and parameters</a> ]</span></span>".
       "<div class='LiveEdit-optionsareadiv' id=\"{\$blockname}_optionsblock\" style=\"display:none; {\$params:FormOptionareaStyle=\"margin:10px;\"}\" ><textarea class='LiveEdit-optionsarea' name='LiveEditOptions_{\$blockname}' rows='2' style='{\$params:FormOptionsInputStyle=\"background-color:#dddddd;\"}'>{\$LiveEdit->OptionsString}</textarea></div>".
       // The buttons
       "<div class='LiveEdit-buttondiv' style=\"{\$params:FormButtonsStyle=\"margin:10px 40px;\"}\">".
       "<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormSaveButtonName}' value='Save this block'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormCancelButtonName}' value='Cancel'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormDeleteButtonName}' value='Delete block'>".
       "&nbsp;&nbsp;&nbsp;&nbsp;<font color='#ffffff'>[<a href='?n=Site.EditQuickReference' target='_blank'>Quick Reference</a>]</font>".
       "<hr style='height:1px;border:none;background-color:#666;margin:5px;'/>".
       "<table border=0 cellpadding=0 cellspacing=0><tr><td><span style='font-weight:bold;color:#ffffff;font-size:1.1em;'>Save and...&nbsp;&nbsp;</span></td><td>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormAddBeforeButtonName}' value='Add block before'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormAddAfterButtonName}' value='Add block after'><br/>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormCopyBeforeButtonName}' value='Copy block before'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormCopyAfterButtonName}' value='Copy block after'>".
       "&nbsp;&nbsp;<input class='LiveEdit-button' type='submit' name='{\$LiveEdit->FormRemoveButtonName}' value='Remove block brackets'>".
       "</td></tr></table></div>".
       // End of form
       "</div></form></div></div></center>";

// For version compatibility:
$LiveEdit->SubTemplates['Form']['CoolForm'] = $LiveEdit->SubTemplates['Form']['Backdrop'];

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

// Form validation sub-template

$LiveEdit->SubTemplates['ValidationJS']['Confirmdelete'] = 
       "<script language='javascript' type='text/javascript'>
            function validateLiveEditForm(theform) {
                //alert('hello');
                return true;
            }
        </script>
       ";

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

// Display block type sub-templates

$LiveEdit->SubTemplates['DisplayType']["Block"] = "block";

$LiveEdit->SubTemplates['DisplayType']["Inline"] = "inline-block";

// -----------------------------------------------------------------

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

// Shortcut menu sub-templates


// -----------------------------------------------------------------
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

/* ========================================================================= */
// The templates (these include the sub-templates)
// The template names should be different from the names of the sub-templates

// Template: standard

$LiveEdit->Templates['Standard'] =
       // The main div block container
       "<div class='LiveEdit-border1' style=\"border:solid 1px #{\$params:BorderColors_0=\"cccccc\"}; margin:0px 5px; padding:0; display:{\$subtemplate:DisplayType=\"Block\"}; \" id=\"{\$blockname}_maindivblock\" >".
       "<script type=\"text/javascript\">
             if (\"{\$subtemplate:DisplayType=\"Block\"}\" == \"inline-block\") {
             var node = document.getElementById('{\$blockname}_maindivblock').parentNode;  
             for(var i=0;i<node.childNodes.length;i++)
                if (node.childNodes[i].id == '{\$blockname}_maindivblock' && i>0)
                   node.childNodes[i-1].style.display = 'inline-block';
          }
        </script>".
       "<div class='LiveEdit-border2' style=\"border:solid 1px #{\$params:BorderColors_1=\"888888\"}; margin:0; padding:0; position:relative; \">".
       // The top bar
       "<div class='LiveEdit-topbar' style=\"{\$params:TopBarStyle=\"height:1.5em; width: 100%; background-color:#cccccc;\"}\"> <a name=\"{\$blockname}_anchor\"></a>".
       "&nbsp;[<a class='LiveEdit-link' id=\"{\$blockname}_editlink\" href=\"javascript:void(0);\" onclick=\"javascript: ".
                     // Javascript to show-hide the form
                     " if (document.getElementById('{\$blockname}_divblock').style.display == 'none' && !document.LiveEdit_FormOpened) { " .
                     "      document.LiveEdit_FormOpened = true; ".
                     "      document.getElementById('{\$blockname}_divblock').style.display = 'block'; " .
                     "      document.getElementById('{\$blockname}_editlink').innerHTML = 'close';  " .
                     " } else { " .
                     "      document.LiveEdit_FormOpened = false; ".
                     "      document.getElementById('{\$blockname}_divblock').style.display = 'none'; " .
                     "      document.getElementById('{\$blockname}_editlink').innerHTML = 'edit';  } ".
       " \">edit</a>] ".
       " </div> ".
       // The edit form
       "{\$subtemplate:ValidationJS=\"Confirmdelete\"}".
       "{\$subtemplate:Form=\"Popup\"}".
       // The Wiki text to be displayed here
       "<div style=\"margin:5px;\">".
       "{\$LiveEdit->DisplayTextPlaceholder}".
       // End of the block
       "</div></div></div>";


// -----------------------------------------------------------------
// Template: phantom

$LiveEdit->Templates['Phantom'] =
       // The main div block container
       "<div class='LiveEdit-border1' style=\"display:{\$subtemplate:DisplayType=\"Block\"}; border:solid 1px #{\$params:BorderColors=\"cccccc\"}; margin:0px 5px; padding:0; position:relative; \" id=\"{\$blockname}_maindivblock\" >".
       "<script type=\"text/javascript\">
             if (\"{\$subtemplate:DisplayType=\"Block\"}\" == \"inline-block\") {
             var node = document.getElementById('{\$blockname}_maindivblock').parentNode;  
             for(var i=0;i<node.childNodes.length;i++)
                if (node.childNodes[i].id == '{\$blockname}_maindivblock' && i>0)
                   node.childNodes[i-1].style.display = 'inline-block';
          }
        </script>".
       "<a name=\"{\$blockname}_anchor\" style=\"margin:0;padding:0;\"></a>".
       // The edit form
       "{\$subtemplate:ValidationJS=\"Confirmdelete\"}".
       "{\$subtemplate:Form=\"Backdrop\"}".
       // The Wiki text to be displayed here
       "<div class='LiveEdit-linkphantom' id=\"{\$blockname}_editlinkbox\" href=\"javascript:void(0);\" ".
                     " onclick=\"javascript: if(!document.LiveEdit_FormOpened) {
                                                 document.getElementById('{\$blockname}_divblock').style.display = 'block'; 
                                                 document.LiveEdit_FormOpened = true; 
                                                 } 
                                             this.style.opacity='1.0'; this.style.filter='alpha(opacity=100)'; \" " .
                     " style=\"{\$params:PhantomStyle=\"margin:0; padding:0; cursor:pointer; cursor:hand;\"}\" ".
                     " onmouseover=\"if(!document.LiveEdit_FormOpened) { {\$params:PhantomMouseOver=\"this.style.opacity='0.4'; this.style.filter='alpha(opacity=40)';\"} }\" ".
                     " onmouseout=\"{\$params:PhantomMouseOut=\"this.style.opacity='1.0'; this.style.filter='alpha(opacity=100)';\"}\">".
       "{\$LiveEdit->DisplayTextPlaceholder}".
       // End of the block
       "</div></div>";


/* ========================================================================= */
/* ========================================================================= */
// Styles (derived from templates)
// ------------------------------------------------------------------------- //

function GetLiveEditStyleHTML($stylename)
{
    global $LiveEdit;
    
    // Choose template
    if ( !($templatename = IsArrayitemInString( array_keys($LiveEdit->Templates), $stylename) ) )
        $templatename = IsArrayitemInString( array_keys($LiveEdit->Templates), $LiveEdit->DefaultStyle);
    $TheHTML = $LiveEdit->Templates[ $templatename ];
    
    // Replace sub-templates
    $ct = 0;
    $count = 1;
    while ($ct++<100 && $count>0)
        $TheHTML = preg_replace("/{\\\$subtemplate:([\w]+)=\\s*\"([^}\"]*?)\"\\s*}/es", 
                        "GetLiveEditSubtemplateHTML('\$1', '".$stylename."', '\$2')", 
                            $TheHTML, -1 , $count);
    return($TheHTML);
}

function IsArrayitemInString($arrk, $str, $falsereturn=null)
{
    // Checks if any of items of $arr is in the $str - case sensitive (unless preceded by "_")
    foreach ($arrk as $k)
        if ( preg_match("/".$k."/", $str) || preg_match("/_".$k."/i", $str) )
            return($k);
    return($falsereturn);
}

function GetLiveEditSubtemplateHTML($groupname, $stylename, $defaultsubtemplate)
{
    global $LiveEdit;
    return ( $LiveEdit->SubTemplates[$groupname][ IsArrayitemInString(array_keys($LiveEdit->SubTemplates[$groupname]), $stylename, $defaultsubtemplate) ] );
}

// --------------
// Listing styles

// Items not to list
$LiveEdit->StyleNoDisplay = array();
$LiveEdit->StyleNoDisplay['Form']['CoolForm'] = true;
$LiveEdit->StyleNoDisplay['ValidationJS'] = true;

function GetLiveEditAllStyles ($styles=null, $subtemplategroupct=0)
{
    global $LiveEdit;
    
    if (!$styles)
        $styles = array_keys($LiveEdit->Templates);
    if ( $subtemplategroupct >= count($LiveEdit->SubTemplates) )
        return($styles);
    
    $allgroups = array_keys( $LiveEdit->SubTemplates );
    $thisgroup = $allgroups[$subtemplategroupct];
    if ( isset($LiveEdit->StyleNoDisplay[$thisgroup]) && $LiveEdit->StyleNoDisplay[$thisgroup]===true )
        return( GetLiveEditAllStyles( $styles, ++$subtemplategroupct) );
    
    $nextstyles = array();
    foreach( $styles as $s )
        foreach ( array_keys($LiveEdit->SubTemplates[$thisgroup]) as $ss )
            if( !isset($LiveEdit->StyleNoDisplay[$thisgroup][$ss]) )
                $nextstyles[] = $s."_".$ss;
                
    return( GetLiveEditAllStyles($nextstyles, ++$subtemplategroupct) );
}

/* ========================================================================= */
/* ========================================================================= */

/* Enable/Disable LiveEdit view + View LiveEdit Styles */
// LiveEdit=true|false|toggle
// LiveEdit=ShowStyle:StyleName|StyleGroup.StylePage

if ($_GET['LiveEdit']) {

    $page = RetrieveAuthPage($pagename, 'edit', true, READPAGE_CURRENT);
    if (!$page)
    {
        setcookie('LiveEdit', "false");
        Redirect($pagename);
    }

    if ($_GET['LiveEdit']=="toggle")
    {
        if ($_COOKIE['LiveEdit']=="true")
            setcookie('LiveEdit', "false");
        else
            setcookie('LiveEdit', "true");
        Redirect($pagename);
        exit;
    }
            
    if ($_GET['LiveEdit']=="true" || $_GET['LiveEdit']=="false")
    {
        setcookie('LiveEdit', $_GET['LiveEdit']);
        Redirect($pagename);
        exit;
    }
    
    if ($_GET['LiveEdit']==="ShowStyle")
    {
        global $LiveEdit;
        $HTML = "<html>".
                "<style type='text/css' media='all'>
                    table { border:solid 1px #888; } 
                    td { border:solid 1px #aaa; padding: 4px; margin: 0; } 
                </style>".
                "<body style='margin:10px 40px; font-family: courier, courier new, monospace;'>";
        $HTML .= "An option string can have one of the folling formats: <ul>
                  <li><b>Style_Name</b></li>
                  <li><b>StyleGroup.StylePage</b></li>
                  <li><b>Style_Name ParamName1=\"ParamValue1\" ParamName2=\"ParamValue2\" . . . </b></li>
                  <li><b>StyleGroup.StylePage ParamName1=\"ParamValue1\" ParamName2=\"ParamValue2\" . . . </b></li>
                 </ul>".
                 "Use the following character encodings for the contents of <b>ParamValue</b><i>n</i>".
                 "<table border=0 cellspacing=0><tr><td><b>character</b></td><td><b>encoding</b></td></tr>";
        for ($a=0; $a<count($LiveEdit->OptionsEncodeChars[0]); $a++)
            $HTML .= "<tr><td>".
                str_replace(array("\n","\r"),array("<i>newline</i>","<i>carriage return</i>"),htmlspecialchars($LiveEdit->OptionsEncodeChars[0][$a])).
                "</td><td>".htmlspecialchars($LiveEdit->OptionsEncodeChars[1][$a])."</td></tr>";
        $HTML .= "</table>&nbsp;<br />Click one of the available <b>Style_Name</b> to view its parameters and their default values</b><br /><br /><b>";
        foreach ( GetLiveEditAllStyles() as $s)
        {
            if ($s==$LiveEdit->DefaultStyle)
                $HTML .= "[ <a href='?n=".$pagename."&LiveEdit=ShowStyle:".$s."'>".$s."</a> ] (default)<br />";
            else
                $HTML .= "[ <a href='?n=".$pagename."&LiveEdit=ShowStyle:".$s."'>".$s."</a> ]<br />";
        }
        $HTML .= "</b><br />Or, type in the <b>StyleGroup.StylePage</b>: <br />
                    &nbsp;&nbsp;<input type='text' id='StyleNameBox' style='margin-top:10px;'/> &nbsp;
                    <input type='button' onclick=\"window.location='?n=".$pagename."&LiveEdit=ShowStyle:'+getElementById('StyleNameBox').value;\" value='Submit' style='margin-top:10px;' /><br />&nbsp;<br />&nbsp;";
        $HTML .= "<hr><input type='button' onclick=\"window.location='?n=".$pagename."';\" value='Exit!' style='width:150px;font-weight:bold;font-size:1.2em;'>";
        $HTML .= "</body></html>";
        print($HTML);
        exit;
    }
    
    if (preg_match("/^ShowStyle:(.*)/e",$_GET['LiveEdit'],$match)===1)
    {
        global $LiveEdit;
        $StyleName = $match[1];
        
        if (!empty($StyleName) && ($stylepage=RetrieveAuthPage($StyleName, 'read', false, READPAGE_CURRENT)) && !empty($stylepage['text'])) 
            $HTML = $stylepage['text'];
        else
            $HTML = GetLiveEditStyleHTML($StyleName);

        if (!empty($paramsST))
            foreach ($paramsST as $k=>$v)
                $HTML = str_replace("{\$paramsST:".$k."}", $v, $HTML);
        $HTML = preg_replace("/[\\n\\r]+/", "", $HTML);
        $HTML = preg_replace("/[\\t\\s]+/", " ", $HTML);
        $newLineTags = "div|p|script|span|form|textarea";
        $HTML = preg_replace("/[\\s]*(<\\/?(".$newLineTags.")*\\b[^>]*>)/i", "\n\\1", $HTML, -1, $count);
        $HTMLarray = explode("\n", $HTML);
        $HTMLfinal = "<html><body style='margin:10px 20px;'>
                      Below is the code for style <b>".$StyleName."</b>. Parameters are displayed in the format 
                      <b><pre>     <span style='background-color:#ccccff; color:#0000ff;'>ParamName</span>=\"<font color='#0000ff'>ParamDefaultValue</font>\"</pre></b>
                      <table border=0 cellpadding=2>";
        $rowbgcolors = array ("ffeeee", "eeeeff");
        $tabdepth = 0;
        foreach ($HTMLarray as $l=>$line)
        {
            if (empty($line)) continue;
            
            if (preg_match("/^<\\/(".$newLineTags.").*/i",$line) === 1) {
                $tabdepth--;
            }
            $HTMLfinal = $HTMLfinal . "<tr style='background-color:#".$rowbgcolors[$l%2].";'>".
                    "<td valign='top' style='width:50px;'><font size=1 color='#cccccc'>".str_repeat("&nbsp;",2*$tabdepth)."</font></td>".
                    "<td valign='top' style='padding-left:". (20*$tabdepth) ."px'>" . str_repeat("&nbsp;",0*$tabdepth) . "<font face='Courier, Courier New, Monospace' size=1>" . htmlspecialchars($line) . "</font></td></tr>\n";
            if (preg_match("/^<(".$newLineTags.").*/i",$line) === 1) {
                $tabdepth++;
            }
            
        }
        $HTMLfinal = $HTMLfinal . "</table>";
        $HTMLfinal = $HTMLfinal . "<hr><input type='button' onclick=\"window.location='?n=".$pagename.
                     "';\" value='Exit!' style='width:150px;font-weight:bold;font-size:1.2em;'>".
                        "</body></html>";
        $HTMLfinal = preg_replace("/{\\\$(.*?)}/", "<b>{\$\\1}</b>",$HTMLfinal);
        $HTMLfinal = preg_replace("/{\\\$LiveEdit-&gt;(.*?)}/", "{<font color='#880000'>\$LiveEdit-&gt;</font>\\1}",$HTMLfinal);
        $HTMLfinal = preg_replace("/{\\\$params:([\w]*)=&quot;(.*?)&quot;}/", "{<font color='#ff0000'>\$params:</font><span style='background-color:#ccccff; color:#0000ff;'>\\1</span>=\"<font color='#0000ff'>\\2</font>\"}",$HTMLfinal);
        
        print($HTMLfinal);
        
        exit;
    }
    
    Redirect($pagename);
    exit;
}

// ==============================================
// helper functions

function LiveEditOptionValueEncode($str)
{
    global $LiveEdit;
    $out = str_replace($LiveEdit->OptionsEncodeChars[0], $LiveEdit->OptionsEncodeChars[1], $str);
    return( $out );
}

function LiveEditOptionValueDecode($str)
{
    global $LiveEdit;
    $out = str_replace($LiveEdit->OptionsEncodeChars[1], $LiveEdit->OptionsEncodeChars[0], $str);
    return( $out );
}

?>