view views/Extractapp/TaggingText.php @ 122:a36bb5a48af4 extractapp tip

1. remove redundancy server side code. 2. All pop up sub-windows are made with dialog component of bootstrap v3.3.2
author Calvin Yeh <cyeh@mpiwg-berlin.mpg.de>
date Thu, 28 Sep 2017 22:26:48 +0200
parents 7f2c5d542616
children
line wrap: on
line source

<?php
/*
 * TaggingText.php
 * This file is part of Extraction-interface.
 *
 * Extraction-interface 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.
 *
 * Extraction-interface 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with Extraction-interface.  If not, see <http://www.gnu.org/licenses/>.
*/

/*! \file
 * This is the view for TaggingText.
 * It shows the extraction-interface application itself.
 * The input data for this view come from models/extractapp.php which is handled by controllers/extractapp.php.
 * Input data for example, are (1)text string (containing tags if there are any),
 * (2)taglist for the current topic, (3)book and section information, etc.
 * The output data are passed to backend by controller to corresponding method in model/extractapp.php.
 * Output data is the tagged text string.
 *
 * The user interface contains tagging area on the left side, and toolbox on the right side.
 * There are popup windows to assist the tagging task, for example RegEx-editors, tag-window, remove-tag-window, etc.
 *
*/

// --- initialize config file and input text ---
$stringInput = $viewmodel['stringInput'];
$wordlistArray = $viewmodel['wordlistArray'];
$taglistArray = $viewmodel['taglistArray'];
$section_id = $viewmodel['section_id'];
$topiclistArray = $viewmodel['topiclistArray'];
$default_topic_id = $viewmodel['default_topic_id'];
$topic_name = $viewmodel['topic_name']; // array of names
$topic_tag = $viewmodel['topic_tag'];
$topic_tag_ch = $viewmodel['topic_tag_ch'];
$info = $viewmodel['info'];
$messages = $viewmodel['messages'];

$taglist_infile = $viewmodel['taglist_infile'];
$book_meta = $viewmodel['book_meta'];

?>


<html>
<head>
    <meta charset="UTF-8">
    <title>Extraction Interface</title>
    <meta http-equiv="no-cache">
    <meta http-equiv="Expires" content="-1">
    <meta http-equiv="Cache-Control" content="no-cache">
    <?php include 'views/maintemplate.php'; ?>
    <script src="../js/jquery.bootstrap-growl.min.js"></script>

<style>
dynasty
{
	color:red;
}
nianhao
{
	color:blue;
}
name
{
	color:orange;
}

body {
  overflow: hidden;
  padding: 15px;
}

#editable-area-wraper {
  height: 90vh;
  overflow: auto;
}

#editable-area {
	line-height:160%;
	letter-spacing:1.5px;
	font-size:21px;
    word-wrap: break-word;
}


<?php
// color on the tags
foreach ( $taglistArray as $taglistValue ) {

    echo $taglistValue[2]."\n{\ncolor:".$taglistValue[3]."; cursor: hand;\n}\n";

    echo ".EditingMode ".$taglistValue[2]."\n{\ncursor: initial;\n}\n";

    echo ".span_".$taglistValue[2]."\n{\nbackground-color:".$taglistValue[3]."\n}\n";
}

?>
</style>

</head>

<body>

<script type="text/javascript">

var cjst = window.cjst; // for pinyin from cjst.js

// not use this for now
function _showTagColor(up_to_date) {
    var taglistArray = "";
    if (up_to_date) {
        taglistArray = JSON.parse('<?php echo json_encode($taglistArray) ?>');
    } else {
        taglistArray = JSON.parse('<?php echo json_encode($taglist_infile) ?>');
    }


    for (var i = 0; i < taglistArray.length; i++) {
        var taglistValue = taglistArray[i];

        $(taglistValue[2]).css('color', taglistValue[3]);
        /*var element = document.querySelectorAll(taglistValue[2]);
        for (var j = 0; j < element.length; j++) {
            element[j].style.color = taglistValue[3];
        }
        */
    }
}


// ---- use cookie to save text and reload page for the up-to-date taglist
function updatePage() {
    var text = getCookie();
    //document.forms['receiver'].elements['message'].value = text;
    if (text == "reload") {
        setCookie("");
        saveTextToLGService();

    }
    setTimeout(updatePage, 500);

}
updatePage();

// ------

function reloadText() {
    /**
     * Reload the text when there is a new version of this branch.
    */
    // confirm to reload
    var r = confirm("Are you sure you want to load the latest version (in a new tab)?");
    if (r != true) {
        return;
    }

    var form = document.createElement("form");
    form.setAttribute("method", "post");
    form.setAttribute("action", "./TaggingText");  // hand to controller
    form.setAttribute("target", "_blank");

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "topic");
    var topic_id = JSON.parse('<?php echo json_encode($default_topic_id) ?>');
    hiddenField.setAttribute("value", topic_id);
    form.appendChild(hiddenField);

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "func");
    hiddenField.setAttribute("value", "ReloadText");
    form.appendChild(hiddenField);

    _postForContineTagging(form);

}

function handleFileVersionConflict() {
    var info = JSON.parse('<?php echo json_encode($info) ?>');
    // if (info['current_fileId'] != 0 && info['current_fileId'] != info['file_id']){
    if (info['current_fileId'] != 0){
        // -- there might be conflicts between different version
        alert("Your saving failed! Someone edited this file and saved before you.");
        $('#reloadTextButton').css("display", "block");

        return;
    }
    return;

}

// on click on tagged words, call removeTagNewDiv() for the popup window
// popup-window overlapping issue
var pop_remove_tag_window = true;
var taglistArray = JSON.parse('<?php echo json_encode($taglistArray) ?>');
for (var i = 0; i < taglistArray.length; i++) {
    var taglistValue = taglistArray[i];


    $(document).on("click", taglistValue[2], function (e, taglistValue) {
        //if ($("#editTextId").html() != "Edit text") return 0;
        if(EditingMode === "editing") return 0;
        var tag = $(this).prop("tagName").toLowerCase();
        //if (tagName != taglistValue[2]) return 0;

        // pop_remove_tag_window is a global variable which indicates if to show the remove-popup-window
        if (pop_remove_tag_window) {
            removeTagNewDiv( e, tag , $(this));

        };
        return false;
  });



};

$(document).ready(function(){

    $("#loading").hide();

    // --- for sidebar---
    //run once
    var el=$('#follow-scroll');
    var originalelpos=el.offset().top; // take it where it originally is on the page

    //run on scroll
    $(window).scroll(function(){
        var el = $('#follow-scroll'); // important! (local)
        var elpos = el.offset().top; // take current situation
        var windowpos = $(window).scrollTop();
        var finaldestination = windowpos+originalelpos;
        //el.stop().animate({'top':finaldestination},500);
        el.stop().animate({'top':finaldestination},0);
    });
    // ---


    //--- for popups ---
    //run once
    var el=$('#popups');
    var originalelpos=el.offset().top; // take it where it originally is on the page

    //run on scroll
    $(window).scroll(function(){
        var el = $('#popups'); // important! (local)
        var elpos = el.offset().top; // take current situation
        var windowpos = $(window).scrollTop();
        var finaldestination = windowpos+originalelpos;
        //el.stop().animate({'top':finaldestination},500);
        el.stop().animate({'top':finaldestination},0);
    });
    // ---


    // === This case only be possible for developing on local machine ====
    var _GET = JSON.parse('<?php echo json_encode($_GET) ?>');
    if (_GET['id']) {
        var info = JSON.parse('<?php echo json_encode($info) ?>');
        var redirectUrl = "http://localhost:1080/localgazetteers-dev/extraction-interface/Extractapp/TaggingText";
        var section_id = info['section_id'];

        var form = $('<form action="' + redirectUrl + '" method="post">' +
            '<input type="hidden" name="sectionId" value="'+section_id+'" />' +
            '</form>');
            $('body').append(form);
            $(form).submit();
    }
    // --------

    // --- handle file version conflict ---
    var info = JSON.parse('<?php echo json_encode($info) ?>');
    // the first time to this section. without branch_id and file_id
    if (info['file_id'] == 0) {  // or info['branch_id'] == 0, means new file
        $( "#save_text_to_LGService_id").text( "Create(Save) Task to LGService" );

    }
    handleFileVersionConflict();

    // --- handle taglist deprecation ---
    var taglist_infile = JSON.parse('<?php echo json_encode($taglist_infile) ?>');
    var taglistArray = JSON.parse('<?php echo json_encode($taglistArray) ?>');

    /*
    if (taglist_infile == "") {
        console.log("Debug: taglist_infile is empty which means taglist_infile is equal to taglist in db.");
    } else {
        console.log("Debug: taglist in file, length=" + taglist_infile.length);
        console.log(taglist_infile);
        console.log("Debug: taglist in db, length=" + taglistArray.length);
        console.log(taglistArray);

        // TOOD: ask user to modify/decide tags (?)
        // showing taglist_infile and taglistArray
    }
    */
    //prevent user paste rich text which means html tag with attributes
    $('[contenteditable]').on('paste', function(e) {
        e.preventDefault();
        var text = '';
        if (e.clipboardData || e.originalEvent.clipboardData) {
          text = (e.originalEvent || e).clipboardData.getData('text/plain');
        } else if (window.clipboardData) {
          text = window.clipboardData.getData('Text');
        }
        if (document.queryCommandSupported('insertText')) {
          document.execCommand('insertText', false, text);
        } else {
          document.execCommand('paste', false, text);
        }
    });
});

$(document).on("mouseup", '#editable-area', function (e) {

    $('.questionMarkClass').remove();
    $('.tagItemDivClass').remove();

    //if ( $("#editTextId").html() != "Edit text" ) return 0;
    if(EditingMode === "editing") return 0;

    //var selection = getSelected();
    selection = getSelected();  // selection is a global variable

    range = selection.getRangeAt(0);    // range is a global variable

    container = document.createElement("div");
    container.appendChild(selection.getRangeAt(0).cloneContents());

    let userTags = {};

    <?php
        foreach ( $taglistArray as $taglistValue ) {
            echo "userTags['".$taglistValue[1]."']='".$taglistValue[2]."';\n";
        }
    ?>

    if(selection && (selection_plain = new String(selection).replace(/^\s+|\s+$/g,''))) {
        //try{
        	var newdiv = document.createElement("div");
            //newdiv.id = "tagItemDivId";
            //newdiv.setAttribute("class", "tagItemDivClass");
            $(newdiv).id = "tagItemDivId";
            $(newdiv).addClass("tagItemDivClass");

            if ( container.innerHTML.indexOf( "br" ) != -1 ) {

                // when selected words containing tags (i.e. has 'br' in the selected string),
                // which means user want to apply Title / or tags all in once at each line
                // This may not be the best checking solution, since 'br' also appears between not-tagged words

                var newselect = document.createElement("select");
                newselect.id = "TitletagType";
                let strTagOpts = '';

                for(let key in userTags){

                     strTagOpts += (`<option value='${userTags[key]}'>${key}</option>`);
                }

                newselect.innerHTML = strTagOpts;

                newdiv.appendChild(newselect);

                //matchValue =  .match();
                myRegexp = new RegExp("〈(.*?)〉", "g")
                matchValue = myRegexp.exec(String(selection));

                newdiv.innerHTML += `<input id='TitletagName' value='${(matchValue) ? matchValue[1] : ''}'>`;
                newdiv.innerHTML += "<div style='text-align:right;margin:3px 0px 8px;'><button class='btn btn-sm btn-primary' onclick=\"addTagTitle(range, container)\">Add Title Tag To Each Line</button><div>";

                /*
                newdiv.innerHTML += "<button onclick=\"exportTable( range, container )\">Export As A Table</button></br></br>";
                */

                var newselect = document.createElement("select");
                newselect.id = "RemoveTitletagType";
                newselect.innerHTML = strTagOpts;
                newdiv.appendChild(newselect);

                newdiv.innerHTML += "<input id=\"RemoveTitletagName\" value=\"\"><br>";
                newdiv.innerHTML += "<div style='text-align:right;margin:3px 0px;'><button class='btn btn-sm btn-default' onclick=\"removeTagTitle( range, container )\">Remove</button></br>";

                let pageY = e.pageY,
                    topPosi = pageY - ( (window.innerHeight - pageY < 145 ) ? 145 : 0);
                newdiv.style.cssText = 'top:'+ topPosi +'; left:'+e.pageX+';';

            } else {

     			// for pop up window on edit-area for tag list
                // newdiv.innerHTML = "Tagging word: "+String(selection)+"<br>";
                var tagging_words = document.createElement("div");
                $(tagging_words).addClass("bg-info");
                $(tagging_words).text("Tagging words: " + String(selection_plain));

                newdiv.appendChild(tagging_words);

                var tagging_tags = document.createElement("div");
                $(tagging_tags).addClass("bg-white");
                $(tagging_tags).text("Tag as: ");

                tagging_tags.innerHTML += "<button class='btn btn-sm btn-primary' accesskey=\"2\" onclick=\"tagwithtitle( range, '"+String(selection_plain)+"' )\">Title</button>";

                var tagBtns_area = document.createElement("div");
                $(tagBtns_area).addClass("tagBtns-area");

                let tagVal,
                    tagging_btns = {R1:[], R2:[], R3:[], R4:[]},
                    aryMainTaggingBtns = [],
                    aryTaggingBtns = [],
                    <?php echo "defaultTopicTag='".$topic_tag."';\n" ?>;

                for(let key in userTags){

                    tagVal = userTags[key];

                    if (tagVal == defaultTopicTag) {
                        aryMainTaggingBtns.push(`<button class='btn btn-primary' accesskey="1" onclick="tagwithOnlytag(range, selection, '${tagVal}2')">${key}</button>`);
                        aryMainTaggingBtns.push(`<button class='btn btn-default' onclick="tagStringWithTag('${String(selection_plain)}', '${tagVal}')">${key}(ALL)</button>`);
                        aryMainTaggingBtns.push(`<button class='btn btn-default' accesskey="1" onclick="tagwithOnlytag(range, selection, '${tagVal}')">${key}(without new line)</button>`);
                    }
                    else{
                        aryTaggingBtns.push(`<button class='btn btn-primary' onclick="tagwithOnlytag(range, selection, '${tagVal}')">${key}</button>`);
                        aryTaggingBtns.push(`<button class='btn btn-default' onclick="tagStringWithTag('${String(selection)}', '${tagVal}')">${key}(ALL)</button>`);
                    }
                }

               var remainder, btnRow;
               for(let idx = 0, len = aryTaggingBtns.length - 1; idx < len; idx = idx + 2){

                   remainder = (idx / 2 % 4) + 1;

                   btnRow = tagging_btns["R" + remainder];
                   btnRow.push(aryTaggingBtns[idx]);
                   btnRow.push(aryTaggingBtns[idx+1]);
               }

               var str_tagging_btns = "";

               if(aryMainTaggingBtns.length > 0){
                  str_tagging_btns = "<tr><td>"
                                    + aryMainTaggingBtns[0] + "</td><td>"
                                    + aryMainTaggingBtns[1] + "</td><td colspan='2'>"
                                    + aryMainTaggingBtns[2] + "</td></tr>";
               }

               for(let idx = 1, len = 4; idx <= len; idx++){

                   btnRow = tagging_btns["R" + idx];

                   if(btnRow.length > 0){

                       str_tagging_btns += ("<tr><td>" + btnRow.join("</td><td>") + "</td></tr>");
                   }
               }

               str_tagging_btns = "<table>" + str_tagging_btns + "</table>";

               tagBtns_area.innerHTML = str_tagging_btns;

               newdiv.appendChild(tagging_tags);
               newdiv.appendChild(tagBtns_area);

               let tagCnt = aryTaggingBtns.length / 2,
                   heightLimit = 109 + ( (tagCnt >= 4) ? 4 : ( tagCnt % 4 ) ) * 32,
                   pageY = e.pageY,
                   topPosi = pageY - ( (window.innerHeight - pageY < heightLimit ) ? heightLimit : 0);

               newdiv.style.cssText = 'top:'+ topPosi +'; left:'+e.pageX+';max-height:280px;';

            }

            //$('#tagItemDivId').addClass();  // tagItemDivId is newdiv's id
            $('body').append(newdiv);
            $('#TitletagType').val(lastAddTag);

            // selected some words, so hide popping up remove-tag-window
            pop_remove_tag_window = false;   // questionMarkID
        // }
        // catch(err){
        //     pop_remove_tag_window = true;   // questionMarkID
        //
        // }
    } else {
        // without selecting any word, so pop up remove-tag-window
        pop_remove_tag_window = true;
    }

    //e.stopPropagation();
});

// === for exporttable.php ===
function exportTable( range, container ) {
    //MsgBox("enter function");
    var form = document.createElement("form");
    form.setAttribute("method", "post");
    form.setAttribute("action", "./ExportTable");
    form.setAttribute("target", "_blank");

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "func");
    hiddenField.setAttribute("value", "exportFromExtractionInterface");
    form.appendChild(hiddenField);

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "content");
    hiddenField.setAttribute("value", container.innerHTML);
    form.appendChild(hiddenField);

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "sectionid");
    hiddenField.setAttribute("value", "<?php echo $section_id; ?>");
    form.appendChild(hiddenField);

    var hiddenField2 = document.createElement("input");
    hiddenField2.setAttribute("name", "topic");
    hiddenField2.setAttribute("value", topic_id);
    form.appendChild(hiddenField2);

    var info = JSON.parse( '<?php echo json_encode($info) ?>');
    var book_meta = JSON.parse( '<?php echo json_encode($book_meta) ?>');

    if (info) {
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "bookId");
        hiddenField.setAttribute("value", info['book_id']);
        form.appendChild(hiddenField);

        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "bookName");
        hiddenField.setAttribute("value", info['book_name']);
        form.appendChild(hiddenField);

        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "sectionName");
        hiddenField.setAttribute("value", info['section_name']);
        form.appendChild(hiddenField);

    };

    if(navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
        document.body.appendChild(form);
        form.submit();
        document.body.removeChild(form);
    } else {
        document.body.appendChild(form);
        form.submit();
        document.body.removeChild(form);
        //form.submit(); // works under IE and Chrome, but not FF
    }
}

var exportMode = "all";

function onExportModeChanged(ele){
     exportMode = ele.value
}

function startExport(topic_id){

     switch(exportMode){
         case "all" :
             exportAll(topic_id);
             break;
         case "pages" :
             exportPage(topic_id);
             break;
     }
}

function exportPage(topic_id) {
    var startPage = $('#exportPageStart').val();
    var endPage = $('#exportPageEnd').val();

    var el = document.getElementById("editable-area");
    var str="" + el.innerHTML;

    var regexText="【<a([^<>]*?)>"+startPage+"</a>】(.*?)【<a([^<>]*?)>"+endPage+"</a>】";

    var form = document.createElement("form");
    form.setAttribute("method", "post");
    form.setAttribute("action", "./ExportTable");
    form.setAttribute("target", "_blank");

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "func");
    hiddenField.setAttribute("value", "exportFromExtractionInterface");
    form.appendChild(hiddenField);

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "content");
    hiddenField.setAttribute("value", str.match(new RegExp(regexText, "g")));
    form.appendChild(hiddenField);

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "topic");
    hiddenField.setAttribute("value", topic_id);
    form.appendChild(hiddenField);

    _postForContineTagging(form);


    /*
    var section_id = JSON.parse('<?php echo json_encode($section_id) ?>');

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "sectionId");
    hiddenField.setAttribute("value", section_id);
    form.appendChild(hiddenField);

    var info = JSON.parse( '<?php echo json_encode($info) ?>');

    if (info) {
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "bookId");
        hiddenField.setAttribute("value", info['book_id']);
        form.appendChild(hiddenField);

        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "bookName");
        hiddenField.setAttribute("value", info['book_name']);
        form.appendChild(hiddenField);

        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "sectionName");
        hiddenField.setAttribute("value", info['section_name']);
        form.appendChild(hiddenField);

    };


    if(navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
        document.body.appendChild(form);
        form.submit();
    } else {
        form.submit(); // works under IE and Chrome, but not FF
    }
    */
}

function exportAll(topic_id) {
    var el = document.getElementById("editable-area");
    var str= "" + el.innerHTML;
    var form = document.createElement("form");
    form.setAttribute("method", "post");
    form.setAttribute("action", "./ExportTable");//+section_id);  // hand to controller
    form.setAttribute("target", "_blank");

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "func");
    hiddenField.setAttribute("value", "exportFromExtractionInterface");
    form.appendChild(hiddenField);



    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "content");
    hiddenField.setAttribute("value", str);
    form.appendChild(hiddenField);

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "topic");
    hiddenField.setAttribute("value", topic_id);
    form.appendChild(hiddenField);

    _postForContineTagging(form);

}

function tagTestX(range, selection, tag) {

    var stringSelection = String(selection);

    saveUndoText();
    var topic_tag = JSON.parse('<?php echo json_encode($topic_tag) ?>');
    var topic_tag2 = topic_tag+"2";


    // stringSelection here only contains plain text (string) without the tagging structure
    // how to use the existing tagging structure

    // ---
    var documentFragment = range.extractContents();


    var tmpStringSelection = ""
    var childNodes = documentFragment.childNodes
    for (var i = 0; i < childNodes.length; i++){

        if (childNodes[i].outerHTML == undefined) {

            tmpStringSelection += childNodes[i].textContent
        } else {

            tmpStringSelection += childNodes[i].outerHTML
        }

    }

    stringSelection = tmpStringSelection;

    range.deleteContents();

    if ( tag==topic_tag2) {
        var newdiv = document.createElement(topic_tag);
        newdiv.innerHTML = stringSelection;
        range.insertNode(newdiv);
        var newdiv = document.createElement("br");
        range.insertNode(newdiv);

    } else {
        var newdiv = document.createElement(tag);
        newdiv.innerHTML = stringSelection;
        range.insertNode(newdiv);
    }


    $('.tagItemDivClass').remove();

    return;

    // TODO if no fragment... bug

    if ( typeof selection !== 'string' ) {
        var next = selection.anchorNode.nextSibling;

        // TODO fragment at the beginning of selection: anchorNode
        var tmpStringSelection = ""

        var startInx = selection.anchorOffset;
        var endSelectionInx = startInx + stringSelection.length;
        var endInx = selection.anchorNode.length;

        var anchorText = selection.anchorNode.textContent;

        /*
        if (selection.anchorNode.nodeType == 3 && next.nodeName != "BR" && next.nodeName != "br") {
        // if (next != null && selection.anchorNode.nodeType == 3 && next.nodeName != "BR" && next.nodeName != "br") {
                // here the anchor node is text

                //tmpStringSelection += anchorText.substring(selection.anchorOffset, selection.anchorNode.length);
                tmpStringSelection += anchorText.substring(startInx, endSelectionInx);

                endInx += endSelectionInx - startInx;

                //endInx += (selection.anchorNode.length - selection.anchorOffset);


        }
        */

        // TODO when anchorNode is not text, but a node


        /*
        if (next != null) {

            if (selection.anchorNode.nodeType == 3 && next.nodeName != "BR" && next.nodeName != "br") {
                var anchorText = selection.anchorNode.textContent
                // never goes here?
                tmpStringSelection += anchorText.substring(selection.anchorOffset, selection.anchorNode.length);


            }
        }
        */

        // TODO parsing stringSelection object in string, with the tagging strucutre

        var checkExtentNode = true

        while(next != null && next != undefined && next.nodeName != "BR" && next.nodeName != "br" ) {

           startInx = endInx

            if (next.nodeType == 3) {   // text case


                endInx += next.textContent.length

                if (endInx > endSelectionInx) {

                    /*
                    tmpStringSelection += next.textContent.substring(0, endSelectionInx-startInx)

                    */

                    //checkExtentNode = false

                    //break;
                } else {

                    tmpStringSelection += next.textContent;

                }



            } else if (next.nodeType == 1) { // node case

                endInx += next.innerHTML.length

                if (endInx > endSelectionInx) {

                    // TODO do something about tmpStringSelection here?

                    //checkExtentNode = false

                    //break;
                } else {


                    tmpStringSelection += next.outerHTML;

                // endInx += next.outerHTML.length
                }


            } else {
                //console.log("[debug] case: nodeType=" + next.nodeType)
            }


            /*

            } else if (next.innerHTML != undefined) {


                endInx += next.innerHTML.length;
                if (endInx >= endSelectionInx) {
                    break;
                }


            } else {
                break
            }

            if (next.outerHTML != undefined) {
                tmpStringSelection += next.outerHTML;
            }
            */

            next = next.nextSibling;

        }


        // TODO
        // fragment at the end of selection: extentNode

        var extentNode = selection.extentNode


        if (checkExtentNode) {

            if (endInx < endSelectionInx && startInx < endSelectionInx ) {
                tmpStringSelection += anchorText.substring(endInx, endSelectionInx);

            } else if (extentNode != null) {
                var extentText = extentNode.textContent

                tmpStringSelection += extentText.substring(startInx, endSelectionInx);

            } else {
                tmpStringSelection += anchorText.substring(startInx, endSelectionInx);
            }
        }

        /*
        if (extentNode != null) {
            if (extentNode.nodeType == 3  ) { // text case
                var extentText = extentNode.textContent

                if (endInx >= endSelectionInx) {

                    tmpStringSelection += extentText.substring(startInx, endSelectionInx);

                } else {
                     tmpStringSelection += anchorText.substring(endInx, endSelectionInx);

                }
            }
        }
        */

        stringSelection = tmpStringSelection;

    }

    range.deleteContents();

    if ( tag==topic_tag2) {
        var newdiv = document.createElement(topic_tag);
        newdiv.innerHTML = stringSelection;
        range.insertNode(newdiv);
        var newdiv = document.createElement("br");
        range.insertNode(newdiv);

    } else {
        var newdiv = document.createElement(tag);
        newdiv.innerHTML = stringSelection;
        range.insertNode(newdiv);
    }


    $('.tagItemDivClass').remove();


}

function tagwithOnlytag( range, selection, tag ) {

    $('#loading').show();

    saveUndoText();
    var topic_tag = JSON.parse('<?php echo json_encode($topic_tag) ?>');
    var topic_tag2 = topic_tag+"2";

    var documentFragment = range.extractContents();

    var stringSelection = ""
    var childNodes = documentFragment.childNodes
    for (var i = 0; i < childNodes.length; i++){
        if (childNodes[i].outerHTML == undefined) {
            stringSelection += childNodes[i].textContent
        } else {
            stringSelection += childNodes[i].outerHTML
        }

    }

    range.deleteContents();

    if ( tag==topic_tag2) {
        var newdiv = document.createElement(topic_tag);
        newdiv.innerHTML = stringSelection;
        range.insertNode(newdiv);
        var newdiv = document.createElement("br");
        range.insertNode(newdiv);

    } else {
        var newdiv = document.createElement(tag);
        newdiv.innerHTML = stringSelection;
        range.insertNode(newdiv);
    }


    $('.tagItemDivClass').remove();

    $('#loading').hide();
}

function tagwithOnlytag_old( range, stringSelection, tag ) {
    saveUndoText();
    var topic_tag = JSON.parse('<?php echo json_encode($topic_tag) ?>');
    var topic_tag2 = topic_tag+"2";

    range.deleteContents();

    if ( tag==topic_tag2) {
        var newdiv = document.createElement(topic_tag);
        newdiv.innerHTML = stringSelection;
        range.insertNode(newdiv);
        var newdiv = document.createElement("br");
        range.insertNode(newdiv);

    } else {
        var newdiv = document.createElement(tag);
        newdiv.innerHTML = stringSelection;
        range.insertNode(newdiv);
    }


    $('.tagItemDivClass').remove();

}

function replaceSmartRegex() {
    saveUndoText();
    var startPage = $('#regexPageStart2').val();
    var endPage = $('#regexPageEnd2').val();

    var el = document.getElementById("editable-area");
    var regexText=document.getElementById("regexText").value;

    <?php
    foreach ( $wordlistArray as $wordlistValue ) {
        echo "\tvar regexText1=\"List ".$wordlistValue[1]."\";\n";
        echo "\tregexText1 = preg_quote(regexText1);\n";
        echo "\tvar replaceText1=\"".$wordlistValue[2]."\";\n";
        echo "\tregexText = regexText.replace(new RegExp(regexText1, \"g\"), replaceText1);\n\n";
    }
    ?>

    var replaceText=document.getElementById("replaceText").value;
    var str="" + el.innerHTML;
    var objReg1 = new RegExp(regexText, "g");
    var occurrences, info;
    if ( startPage == "" ) {

        occurrences = (str.match(objReg1)||[]).length;

        if(occurrences > 0){
            info = "Replaced "+ occurrences +" entities.";
            el.innerHTML = str.replace(objReg1, replaceText);
        }
    } else {
        var regexText2="【<a([^<>]*?)>"+startPage+"</a>】(.*?)【<a([^<>]*?)>"+endPage+"</a>】";
        var objReg2 = new RegExp(regexText2, "g");
        var partString = "" + str.match(objReg2);
        //alert(partString);

        occurrences = (partString.match(objReg1)||[]).length;

        if(occurrences > 0){
            info = "Replaced "+ occurrences +" entities.";
            var resultString = partString.replace(objReg1, replaceText);

            str = "" + el.innerHTML;
            el.innerHTML = str.replace(objReg2, resultString);
        }
    }

    if(occurrences == 0) info = "Found 0 occurrence.";

    $.bootstrapGrowl(info);
    //document.styleSheets[0].addRule("tag001", "color:green;")
}

function saveTextToLGService() {
    // clean editable-area
    $('.questionMarkClass').remove();
    $('.tagItemDivClass').remove();

    // -------------
    var info = JSON.parse('<?php echo json_encode($info) ?>');
    var topic_id = JSON.parse('<?php echo json_encode($default_topic_id) ?>');

    // if this is a new branch, ask for label
    // if (info['branch_id'] == 0) {
    if (info['branch_id'] == 0) {
        //var label = prompt("Please enter your label for this new branch", "section"+info['section_id']);
        var today = new Date();
        var dd = today.getDate();
        var mm = today.getMonth()+1; //January is 0!
        var yyyy = today.getFullYear();

        if(dd<10) {
            dd='0'+dd
        }
        if(mm<10) {
            mm='0'+mm
        }
        today = dd+'.'+mm+'.'+yyyy;
        var book_name = info['book_name'];
        var section_name = info['section_name'];
        var period = info['period'];

        var default_label = "";
        if (book_name == "" || section_name == "" || period == "") {
            default_label = today;
        } else {
            default_label = book_name + "(" + cjst.chineseToPinyin(book_name).join(' ') + ")_"
                            + period + "(" + cjst.chineseToPinyin(period).join(' ') + ")_"
                            + section_name + "(" + cjst.chineseToPinyin(section_name).join(' ') + ")_"
                            + today;
        }


        var label = prompt("Please enter your label for this new task", default_label);
        while (label == null) {
            alert("You haven't saved your editing.");
            return;
        }
    };

    var form = document.createElement("form");
    form.setAttribute("method", "post");
    form.setAttribute("action", "./TaggingText");  // hand to controller
    form.setAttribute("target", "_self");

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "func");
    hiddenField.setAttribute("value", "SaveFullTextToLGService");
    form.appendChild(hiddenField);


    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "label");
    hiddenField.setAttribute("value", label);
    form.appendChild(hiddenField);

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "topic");
    hiddenField.setAttribute("value", topic_id);
    form.appendChild(hiddenField);

    _postForContineTagging(form);

    // set Cookies to triger LGService to reload for the up-to-date version
    var value = 1;
    document.cookie = "saveTextToLGService=" + value + "; path=/LGServices/pages";

}

function createTopic(default_topic_id) {
    var popup_status = $('#new_topic_div').css("display");
    if (popup_status == "block") {
        $('#new_topic_div').css("display", "none");
    } else {
        $('#new_topic_div').css("display", "block");
    }

    var newtopic = document.getElementById("newTopicSubmit");

    newtopic.onclick = function(){
        // check if all fields are filled in
        if ($("#newTopicNameEn").val()==""|| $("#newTopicNameCh").val()=="" || $("#newTopicNamePi").val()=="" ||
            $("#newTopicTag").val()=="" || $("#newTopicTagName").val()=="") {
            alert("Please fill in all the fields for the new topic.");
            return;
        }


        var form = document.createElement("form");
        form.setAttribute("method", "post");
        form.setAttribute("action", "./TaggingText");  // hand to controller
        form.setAttribute("target", "_self");

        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "func");
        hiddenField.setAttribute("value", "CreateNewTopic");
        form.appendChild(hiddenField);

        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "new_topic_name_en");
        hiddenField.setAttribute("value", $("#newTopicNameEn").val());
        form.appendChild(hiddenField);
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "new_topic_name_ch");
        hiddenField.setAttribute("value", $("#newTopicNameCh").val());
        form.appendChild(hiddenField);
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "new_topic_name_pi");
        hiddenField.setAttribute("value", $("#newTopicNamePi").val());
        form.appendChild(hiddenField);
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "new_topic_tag");
        hiddenField.setAttribute("value", $("#newTopicTag").val());
        form.appendChild(hiddenField);
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("name", "new_topic_tag_name");
        hiddenField.setAttribute("value", $("#newTopicTagName").val());
        form.appendChild(hiddenField);


        _postForContineTagging(form);

    }

    $("#newTopicCancel").attr("onclick", "$('#new_topic_div').css(\"display\", \"none\");");

}

function chooseTopic(default_topic_id) {
    var t = JSON.parse( '<?php echo json_encode($topiclistArray) ?>' );
    var info = JSON.parse('<?php echo json_encode($info) ?>');

    $('#load_topic_div').html("");
    var popup_status = $('#load_topic_div').css("display");
    if (popup_status == "block") {
        $('#load_topic_div').css("display", "none");
    } else {
        $('#load_topic_div').css("display", "block");
    }
    /*
    $('#load_topic_div').css("border", "1px solid black");
    $('#load_topic_div').css("background-color", "White");
    $('#load_topic_div').css("width", "200px");
    $('#load_topic_div').css("height", "50px");
    $('#load_topic_div').css("top", "20px");
    $('#load_topic_div').css("left", "-200px");
    */

    var topic_select = document.createElement("select");
    topic_select.id = "loadTopiclist";
    var selected_topic = t[0];
    topic_select.onchange = function(){

        var changeConfirm = confirm("You're going to change topic. \nUnsaved data will be lost.");

        if (changeConfirm) {

        	selected_topic = topic_select.options[topic_select.selectedIndex];

        	var topic_id = selected_topic.value;

    		var form = document.createElement("form");
            form.setAttribute("method", "post");
            form.setAttribute("action", "./TaggingText");  // hand to controller
            form.setAttribute("target", "_self");

            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "topic");
            hiddenField.setAttribute("value", topic_id);
            form.appendChild(hiddenField);

            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "func");
            hiddenField.setAttribute("value", "ContinueTagging");
            form.appendChild(hiddenField);

    	    _postForContineTagging(form);


        } else {
            return
        }
    };


    //Create and append the options
	for (var i = 0; i < t.length; i++) {
    	var option = document.createElement("option");
    	option.value = t[i]['id'];
	    option.text = t[i]['name_en']+" ("+t[i]['name_ch']+", "+t[i]['name_pinyin']+")";
	    if (option.value == default_topic_id) {
	    	option.selected = true;
	    };
	    topic_select.appendChild(option);
	}

    var newbutton = document.createElement("button");
    $(newbutton).html('<span aria-hidden=\"true\">×</span>');
    $(newbutton).addClass("btn btn-xs btn-default close-btn");
    $(newbutton).attr("onclick", "$('#load_topic_div').css(\"display\", \"none\");");
    $('#load_topic_div').append(newbutton);

    $('#load_topic_div').append(topic_select);

}

function _postForContineTagging(form) {
    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "text");
    var el = document.getElementById("editable-area");
    var text = el.innerHTML;
    hiddenField.setAttribute("value", text);
    form.appendChild(hiddenField);

    // pass taglist
    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "taglistArray");

    // use json_encode($taglistArray), which is the up-to-date taglist (in db) instead,
    // so replace the follwoing code
    /*
    var taglistObj = JSON.parse('<?php echo json_encode($taglist_infile) ?>');
    // if taglist_infile == "" means the taglist in db is up-to-date, will use taglistArray to save to file

    if (!taglistObj) {
        // TODO: should pass the user-decided taglist to post['taglistArray']
        taglistObj = JSON.parse('<?php echo json_encode($taglistArray) ?>');
    }
    taglistArray = JSON.stringify(taglistObj);
    */


    var taglistArray = JSON.parse('<?php echo json_encode($taglistArray) ?>');
    hiddenField.setAttribute("value", taglistArray);
    form.appendChild(hiddenField);

    // pass book_meta
    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "book_meta");
    var book_metaObj = JSON.parse('<?php echo json_encode($book_meta) ?>');
    book_metaArray = JSON.stringify(book_metaObj);

    hiddenField.setAttribute("value", book_metaArray);
    form.appendChild(hiddenField);


    var info = JSON.parse( '<?php echo json_encode($info) ?>');

    if (info) {
        if (info['file_id']) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "fileId");
            hiddenField.setAttribute("value", info['file_id']);
            form.appendChild(hiddenField);
        };
        if (info['branch_id']) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "branchId");
            hiddenField.setAttribute("value", info['branch_id']);
            form.appendChild(hiddenField);
        };
        if (info['user_id']) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "userId");
            hiddenField.setAttribute("value", info['user_id']);
            form.appendChild(hiddenField);
        };
        if (info['section_id']) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "sectionId");
            hiddenField.setAttribute("value", info['section_id']);
            form.appendChild(hiddenField);
        };
        if (info['book_id']) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "bookId");
            hiddenField.setAttribute("value", info['book_id']);
            form.appendChild(hiddenField);
        };
        if (info['section_name']) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "sectionName");
            hiddenField.setAttribute("value", info['section_name']);
            form.appendChild(hiddenField);
        };
        if (info['book_name']) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "bookName");
            hiddenField.setAttribute("value", info['book_name']);
            form.appendChild(hiddenField);
        };
        if (info['current_fileId']) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("name", "currentFileId");
            hiddenField.setAttribute("value", info['current_fileId']);
            form.appendChild(hiddenField);
        };

    }

        document.body.appendChild(form);
        form.submit();
        document.body.removeChild(form);


}

function configTagsInTopic(topic_id) {
    var form = document.createElement("form");

    form.setAttribute("method", "post");
    form.setAttribute("action", "./ConfigTagsInTopic");  // hand to controller
    form.setAttribute("target", "_blank");

    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("name", "topic");
    hiddenField.setAttribute("value", topic_id);
    form.appendChild(hiddenField);

    _postForContineTagging(form);


}

var toolPanelPosition = "right";

function moveToolPanel(toWhere){

  if(toolPanelPosition == toWhere) return;

  var oldAreaId, newAreaId, oldBtn, newBtn;
  if(toWhere == "left"){
     oldAreaId = 'right-tool-bar-area';
     newAreaId = 'left-tool-bar-area';
     oldBtn = 'toLeft';
     newBtn = 'toRight';
  }
  else{
     oldAreaId = 'left-tool-bar-area';
     newAreaId = 'right-tool-bar-area';
     oldBtn = 'toRight';
     newBtn = 'toLeft';
  }

  var oldParent = document.getElementById(oldAreaId),
      newParent = document.getElementById(newAreaId);

  while (oldParent.hasChildNodes()){
    newParent.appendChild(oldParent.firstChild);
  }

  newParent.style.display = "block";
  oldParent.style.display = "none";

  document.getElementById(newBtn).firstChild.style.display = "block";
  document.getElementById(oldBtn).firstChild.style.display = "none";

  toolPanelPosition = toWhere;

}

$(document).on("change", '#smartRegexPopUpSelectWord', function (e) {
    var wordlistArray = JSON.parse('<?php echo json_encode($wordlistArray) ?>');

    for (var i = 0; i < wordlistArray.length; i++) {
        var wordlistValue = wordlistArray[i];   // wordlistValue is array(id, name, listString)
        if ($('#smartRegexPopUpSelectWord').val() == wordlistValue[0]) {
            var textarea_text = $('#smartRegexPopUpText').val();
            // insert selected wordlist into textarea at cursor position
            var cursorPosition = $('#smartRegexPopUpText').prop("selectionStart");
            // cut textarea_text by cursorPosition
            var text_before_cursor = textarea_text.substring(0,cursorPosition);
            var text_after_cursor = textarea_text.substring(cursorPosition, textarea_text.length);

            // default length is 1, which means {1,1}
            $('#smartRegexPopUpText').val( text_before_cursor+"["+wordlistValue[2]+"]{1,1}"+text_after_cursor);
        }
    }
});

</script>

<div id="loading">...</div>

<div class="container-fluid info-board">
    <div class="row">
      <div class="bg-danger"><strong><?php echo $messages['error']; ?> </strong></div>
      <div class="bg-warning"> <?php echo $messages['warning']; ?>
          <button id="reloadTextButton" onclick="reloadText(<?php echo $default_topic_id; ?>)" style="display:none;">Latest Version</button>
      </div>
      <div class="bg-info"> <?php echo $messages['info']; ?> </div>
    </div>
</div>

<div class="container-fluid">
    <div class="row">
        <div id="left-tool-bar-area" class="col-md-3 tool-col" style="display:none"></div>
        <div class="col-md-9 content-col">
          <div id="editable-area-wraper">
            <div id="editable-area" class="area" contenteditable="false"><?php echo $stringInput; ?></div>
          </div>
        </div>
        <div id="right-tool-bar-area" class="col-md-3 tool-col">
            <div id="popups" style="position:absolute; width:300px; ">
                <div id="load_topic_div" class="popup-topic popup-frame"></div>
                <div id="new_topic_div" class="popup-newtopic popup-frame">
                    <div class="form-horizontal">
                        <h4 class="text-info">New topic name:</h4>
                        <div class="form-group form-group-sm">
                            <label for="newTopicNameEn" class="col-sm-5 control-label">name (eng)</label>
                            <div class="col-sm-7">
                                <input type="text" class="form-control" id="newTopicNameEn" placeholder="e.g. Local Product">
                            </div>
                         </div>
                        <div class="form-group form-group-sm">
                            <label for="newTopicNameCh" class="col-sm-5 control-label">name (中文)</label>
                            <div class="col-sm-7">
                                <input type="text" class="form-control" id="newTopicNameCh" placeholder="e.g. 物產">
                            </div>
                        </div>
                        <div class="form-group form-group-sm">
                            <label for="newTopicNamePi" class="col-sm-5 control-label">name (pinyin)</label>
                            <div class="col-sm-7">
                                <input type="text" class="form-control" id="newTopicNamePi" placeholder="e.g. wu chan">
                            </div>
                        </div>


                        <h4 class="text-info">Define the topic tag for the new topic:</h4>
                        <div class="form-group form-group-sm">
                            <label for="newTopicTag" class="col-sm-5 control-label">topic tag (eng)</label>
                            <div class="col-sm-7">
                                <input type="text" class="form-control" id="newTopicTag" placeholder="e.g. product_name">
                            </div>
                        </div>

                        <div class="form-group form-group-sm">
                            <label for="newTopicTagName" class="col-sm-5 control-label">topic tag (中文)</label>
                            <div class="col-sm-7">
                                <input type="text" class="form-control" id="newTopicTagName" placeholder="e.g. 物產名稱">
                            </div>
                        </div>


                        <div class="form-group form-group-sm">
                            <div class="col-sm-offset-5 col-sm-7">
                                <button type="submit" id="newTopicSubmit" class="btn btn-primary btn-xs">Submit</button>
                                <button id="newTopicCancel" class="btn btn-default btn-xs">Cancel</button>
                            </div>
                        </div>
                    </div>

                </div>
                <div id="load_regex_div" class="popup-loadregex popup-frame"></div>
                <div id="regex_generator" class="popup-frame">
                    <h3>Gen Regex</h3>
                    <div>Pattern 1:
                        <div id="regex_pattern1" class="bg-info"></div>
                    </div>
                    <div>Pattern 2:
                        <div id="regex_pattern2" class="bg-info"></div>
                    </div>
                    <div>Suggested Regex:
                        <div id="generated_regex" class="bg-success"></div>
                    </div>
                    <button onclick="genRegexAddToSmartRegex()" class="btn btn-info">Add it to SmartRegex</button>
                    <button onclick="genRegexWindowClose()" class="btn btn-default">Close</button>
                    <div id="regex_generator_error_msg" class="bg-white"></div>
                </div>
                <div id="smartRegexPopUpDiv" class="popup-frame">

                    Name: <input id="smartRegexPopUpName"></input>
                    <button onclick="replaceSmartClose()" class="btn btn-sm btn-default close-btn" ><span aria-hidden="true">×</span></button><br><br>
                    Word List:
                    <select id="smartRegexPopUpSelectWord">
                    <option value="NULL" selected>無</option>
                    <?php
                        foreach ( $wordlistArray as $wordlistValue ) {
                            echo "<option value=\"".$wordlistValue[0]."\">".$wordlistValue[1]."</option>\n";
                        }
                    ?>
                    </select>
                    <!-- edit wordlist -->
                    <button onclick="window.open('./EditWordlist')" class="btn btn-sm btn-default">Edit WordList</button></br>

                    <br>
                    OR (USE "|" TO SEPARATE WORDS):<br>
                    <TEXTAREA id="smartRegexPopUpText" COLS=59 ROWS=4 style="width:100%;"></TEXTAREA><br><br>
                    Tag:
                    <select id="smartRegexPopUpSelectTag">
                    <?php
                        foreach ( $taglistArray as $taglistValue ) {
                            echo "<option value=\"".$taglistValue[2]."\">".$taglistValue[1]."</option>\n";
                        }
                        echo "<option value=\"title\">Title</option>\n";
                    ?>
                    <option value="NOTAG">不標記</option>
                    </select><br><br>
                    <button id="smartRegexPopUpBack" onclick="replaceSmartBack()" class="btn btn-sm btn-default"><<</button>
                    <button id="smartRegexPopUpAdd" onclick="replaceSmartAdd()" class="btn btn-sm btn-info" style="display:none">Add</button>
                    <button id="smartRegexPopUpDel" onclick="replaceSmartRemove()" class="btn btn-sm btn-danger">Remove</button>
                    <button id="smartRegexPopUpEdit" onclick="replaceSmartEdit()" class="btn btn-sm btn-success">Edit/Update</button>
                    <button id="smartRegexPopUpFor" onclick="replaceSmartFor()" class="btn btn-sm btn-default">>></button>
                </div>
            </div>
            <div id="toLeft" onclick="moveToolPanel('left')"><span class="glyphicon glyphicon-arrow-left switch-btn"></span></div>
            <div id="follow-scroll">
              <div class="panel panel-default" style="margin-bottom: 10px;">
                  <div class="panel-body" style="padding:5px;">
                    Current topic is : <?php echo $topic_name['name_en']; ?> (<?php echo $topic_name['name_ch']; ?>, <?php echo $topic_name['name_pinyin']; ?>)
                  </div>
              </div>

              <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
                <div class="panel panel-default">
                  <div class="panel-heading" role="tab" id="headingOne">
                    <h4 class="panel-title">
                      <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
                        Change Topic and Tags: <span class="caret"></span>
                      </a>
                    </h4>
                  </div>
                  <div id="collapseOne" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
                    <div class="panel-body">
                      <button onclick="chooseTopic(<?php echo $default_topic_id;?>)" class="btn btn-info btn-block">Change Topic</button>
                      <br>

                      <div>Main tag: <?php echo $topic_tag_ch;?>
                          <p class="text-muted">(Only the lines with the tag will be in the exported table.)</p>
                      </div>
                      <button onclick="editTaglist(<?php echo $default_topic_id; ?>)" class="btn btn-primary btn-block">Edit Tag List</button>
                      <!-- <button onclick="configTagsInTopic(< ?php echo $default_topic_id;? >)" class="btn btn-default btn-block">Select Existing Tags (testing)</button> -->
                    </div>
                  </div>
                </div>

                <div class="panel panel-default">
                  <div class="panel-heading" role="tab" id="headingTwo">
                    <h4 class="panel-title">
                      <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
                        Edit, Tag, Save text : <span class="caret"></span>
                      </a>
                    </h4>
                  </div>
                  <div id="collapseTwo" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingTwo">
                    <div class="panel-body">

                        <!-- <button onclick="editText()" id="editTextId" class="btn btn-default">Edit text</button> -->
                        <div class="btn-group" data-toggle="buttons">
                          <label class="btn btn-default btn-sm active" onclick="switchToTaggingMode(this, 'tagging')">
                            <input type="radio" name="EditMode" value="tagging" autocomplete="off" checked> Tagging
                          </label>
                          <label class="btn btn-default btn-sm" onclick="switchToEditingMode(this, 'editing')">
                            <input type="radio" name="EditMode" value="editing" autocomplete="off"> Editing
                          </label>
                        </div>
                        <button onclick="Undo()" class="btn btn-sm btn-default" id="buttonUndo" disabled="true" style="float:right;">Undo changes</button>

                        <div id="smart-regex-area" class="sub-group-area"><span><i><b>Smart Regex</b></i>©</span>
                             <div id="smartRegexShowDiv"></div>
                             <!-- <button onclick="smartRegexNew()" class="btn-lg">Add Regex Group</button></br> -->
                               <button onclick="smartRegexNew()" id="smart_regex_new_id" class="btn btn-sm btn-info">Compose</button>
                               <button onclick="smartRegexLoad(<?php echo $default_topic_id; ?>)" class="btn btn-sm btn-info">Load</button>
                               <button onclick="smartRegexSave(<?php echo $default_topic_id; ?>)" class="btn btn-sm btn-default" style="float:right;">Save</button>
                               <button onclick="smartRegexEmpty()" class="btn btn-sm btn-danger" style="float:right;margin-right:4px">Clear</button>
                             </div>
                         <div>
                        <div id="tag-function-area" class="sub-group-area">
                            Tag only for this range:
                            <input type="text" size="5" id="regexPageStart"> to <input type="text" size="5" id="regexPageEnd"><br><br>

                            <div>
                              <label>
                                 <input type="radio" name="tagging_mode" onclick="onTagModeChanged(this)" value="default" checked> Default
                              </label>
                            </div>
                            <div>
                              <label>
                                 <input type="radio" name="tagging_mode" onclick="onTagModeChanged(this)" value="with_line_break"> With line break
                              </label>
                            </div>
                            <!--
                            <div>
                              <label>
                                 <input type="radio" name="tagging_mode" onclick="onTagModeChanged(this)" value="space_within_block"> Allow space within block
                              </label>
                            </div>
                            -->
                            <div style="text-align:right"><button onclick="startToTag()" class="btn btn-primary">Tag</button></div>
                        </div>
                        <button onclick="saveTextToLGService()" id="save_text_to_LGService_id" class="btn btn-primary btn-block" style="margin-top:10px;">Save text</button>

                    </div>
                  </div>
                </div>

                <div class="panel panel-default">
                  <div class="panel-heading" role="tab" id="headingThree">
                    <h4 class="panel-title">
                      <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
                        Replace By <i><b>Regex</b></i>: <span class="caret"></span>
                      </a>
                    </h4>
                  </div>
                  <div id="collapseThree" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree">
                    <div class="panel-body">
                      Range: <input type="text" size="5" id="regexPageStart2"> to <input type="text" size="5" id="regexPageEnd2"><br><br>
                      Regex: <input type="text" size="23" id="regexText"><br><br>
                      Replace: <input type="text" size="23" id="replaceText"><br><br>
                      <div style="text-align:right"><button onclick="replaceSmartRegex()" class="btn btn-primary btn-sm">Replace</button></div>
                    </div>
                  </div>
                </div>

                <div class="panel panel-default">
                  <div class="panel-heading" role="tab" id="headingFour">
                    <h4 class="panel-title">

                      <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseFour" aria-expanded="false" aria-controls="collapseFour">
                        <!-- Tag by <i><b>Smart Regex</b></i>©:<span class="caret"></span> -->
                        Preview<span class="caret"></span>
                      </a>
                    </h4>
                  </div>
                  <div id="collapseFour" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingFour">
                    <div class="panel-body">

                      <div>
                        <label>
                           <input type="radio" name="export_mode" onclick="onExportModeChanged(this)" value="all" checked> All
                        </label>
                      </div>
                      <div>
                        <label>
                           <input type="radio" name="export_mode" onclick="onExportModeChanged(this)" value="pages">
                           Page: <input type="text" size="5" id="exportPageStart"> to <input type="text" size="5" id="exportPageEnd">
                      </div>

                      <div style="text-align:right"><button onclick="startExport(<?php echo $default_topic_id;?>)" class="btn btn-primary btn-sm">Preview</button></div>
                    </div>

                  </div>
                </div>

              </div>

            </div>
            <div id="toRight" onclick="moveToolPanel('right')"><span class="glyphicon glyphicon-arrow-right switch-btn" style="display:none"></span></div>
        </div>

    </div>

</div>




</body>

</html>