changeset 121:21e89eca0b84 extractapp

All pop 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 17:51:53 +0200
parents 71b611a676c3
children a36bb5a48af4
files css/taggingtext.css js/taggingtext.js
diffstat 2 files changed, 532 insertions(+), 301 deletions(-) [+]
line wrap: on
line diff
--- a/css/taggingtext.css	Thu Sep 28 17:48:35 2017 +0200
+++ b/css/taggingtext.css	Thu Sep 28 17:51:53 2017 +0200
@@ -36,11 +36,8 @@
 
 
 .info-board{
-	margin:10 30 10 30;
-	width: 100%;
-	max-width:1270px;
-	min-width: 680px;
 	border: 2px solid #A1A1A1;
+	margin-bottom:10px;
     border-radius: 4px;
 	max-height:70px;
 	overflow:scroll;
@@ -49,12 +46,16 @@
 
 
 #follow-scroll {
-	position:absolute; 
-	height:680px; 
-	overflow:scroll; 
-	margin:5 0 15 0; 
-	padding: 0 0 30 0;
-	max-width:270px; 
+	height:90vh;
+    width: 90%;
+	overflow:auto;
+    padding-top: 10px;
+    float: left;
+}
+
+#follow-scroll #accordion .panel-body {
+
+    height: 55vh;
 }
 
 .tool-frame{
@@ -71,20 +72,26 @@
 
 .popup-frame {
 	position: absolute;
-	display: none; 
+	display: none;
 	background-color: white;
 	border: 2px solid #A1A1A1;
 	border-radius: 4px;
-	padding: 5px;	
+	padding: 5px;
 }
 
 #smartRegexPopUpDiv{
-	left: -450px;
 	width: 450px;
-	height: 300px;
+	height: 320px;
 	top: 120px;
 	z-index: 2;
+}
 
+#right-tool-bar-area #smartRegexPopUpDiv{
+	left: -450px;
+}
+
+#left-tool-bar-area #smartRegexPopUpDiv{
+	left: 350px;
 }
 
 #regex_generator {
@@ -96,23 +103,59 @@
 
 }
 
-
 .popup-loadregex{
-	left: -300px;
 	width: 300px;
-	height: 85px;
+	height: 110px;
 	top: 100px;
 	z-index: 3;
+}
 
+#right-tool-bar-area #load_regex_div {
+	left: -300px;
+}
+
+#left-tool-bar-area #load_regex_div {
+	left: 350px;
 }
 
 .popup-topic {
-	left: -250px;
 	width: 250px;
 	height: 80px;
 	top: 20px;
 	z-index: 2;
 }
+
+.popup-topic .close-btn,
+.popup-loadregex .close-btn,
+#smartRegexPopUpDiv .close-btn {
+	float: right;
+	margin-bottom: 15px;
+}
+
+
+.popup-loadregex .emptyRow {
+    height: 30px;
+    text-align: right;
+    padding-top: 10px;
+}
+
+.popup-loadregex #loadRegexSelect {
+    margin-right: 10px;
+    width: 100%;
+}
+
+#right-tool-bar-area #load_topic_div{
+   left: -250px;
+}
+
+#left-tool-bar-area #load_topic_div{
+   left: 350px;
+}
+
+#loadTopiclist {
+   width: 235px;
+}
+
 .popup-newtopic {
 	left: -360px;
 	width: 360px;
@@ -120,23 +163,23 @@
 	top: 100px;
 	z-index: 2;
 	overflow:scroll;
-	overflow-x:hidden; 
+	overflow-x:hidden;
 }
 .tagItemDivClass {
-	position:absolute; 
-	background-color: white; 
+	position:absolute;
+	background-color: white;
 	border: 2px solid #A1A1A1;
-	border-radius: 4px;	
-	padding: 5px; 
+	border-radius: 4px;
+	padding: 5px;
 	z-index:5;
 }
 
 .questionMarkClass {
-	position:absolute; 
-	background-color: white; 
+	position:absolute;
+	background-color: white;
 	border: 2px solid #A1A1A1;
-	border-radius: 4px;	
-	padding: 5px; 
+	border-radius: 4px;
+	padding: 5px;
 	z-index:4;
 }
 
@@ -158,3 +201,80 @@
 	font-size:20px;
 	line-height:20px;
 }
+
+.sub-group-area {
+	border: 1px solid #ddd;
+  border-radius: 4px;
+	padding: 5px;
+  margin: 10px 0px;
+}
+
+#smartRegexShowDiv {
+	border: 1px solid #EEE;
+	min-height: 30px;
+	padding: 5px;
+	margin-bottom: 5px;
+}
+
+#smartRegexShowDiv span{
+    cursor: hand;
+}
+
+.EditingMode {
+    background-color: #fff !important;
+    box-shadow: inset 3px 3px 5px rgba(0,0,0,.125);
+    border-color: red !important;
+}
+
+.content-col,
+.tool-col {
+    border:1px solid #A1A1A1;
+}
+
+.tool-col {
+    padding: 0px !important;
+}
+
+#toLeft {
+   width: 15px;
+   float: left;
+    height: 20px;
+    top: 17px;
+    position: relative;
+}
+
+#toRight {
+    width: 15px;
+    float: right;
+    height: 20px;
+    top: 17px;
+    position: relative;
+}
+
+.tagBtns-area {
+    margin-top: 5px;
+    max-height: 220px;
+}
+
+.tagBtns-area td{
+   padding: 2px 2px 4px;
+}
+
+.tagBtns-area button {
+   padding: 3px 8px;
+}
+
+.questionMarkClass button  {
+   padding: 3px 8px;
+   margin-right: 3px;
+   margin-top: 3px;
+}
+
+.questionMarkClass .removeTagText,
+.tagItemDivClass .bg-info {
+   max-width: 600px;
+   text-overflow: ellipsis;
+   white-space: nowrap;
+   overflow: hidden;
+   display:block;
+}
--- a/js/taggingtext.js	Thu Sep 28 17:48:35 2017 +0200
+++ b/js/taggingtext.js	Thu Sep 28 17:51:53 2017 +0200
@@ -16,10 +16,10 @@
  * along with Extraction-interface.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-/*! \file  
- * There are javscript functions for Extractapp. 
+/*! \file
+ * There are javscript functions for Extractapp.
  * It is included by views/Extractapp/maintemplate.php and maintemplate_local.php.
-*/ 
+*/
 
 // === for taggingtext.php ===
 var stringBeforeChange="";
@@ -36,6 +36,7 @@
     document.cookie = "cookie-msg-test=" + value + "; path=/";
     return true;
 }
+
 function getCookie() {
     var cname = "cookie-msg-test=";
     var ca = document.cookie.split(';');
@@ -55,7 +56,7 @@
     e.stopPropagation();
     $('.questionMarkClass').remove();
     $('.tagItemDivClass').remove();
-    alert("Remove");
+    $.bootstrapGrowl("Remove");
 });
 
 
@@ -72,19 +73,20 @@
     var replaceText="<time>$1$2$3$4$5$6$7$8$9</time>";
     var matchedCount = str.match(regexText).length;
     str = str.replace(regexText, replaceText);
-    
+
     var regexText=/(?!(>))(<?php echo $wordlistArray[0][2]; ?>)/g;
     var replaceText="<time>$1$2</time>";
     matchedCount += str.match(regexText).length;
     el.innerHTML = str.replace(regexText, replaceText);
-    
+
     var regexText=/(一|二|三|四|五|六|七|八|九)?(○?)(十)?(○?)(一|二|三|四|五|六|七|八|九|元|十)(○?)(年)(?!(<))/g;
     var replaceText="<time>$1$2$3$4$5$6$7</time>";
     matchedCount += str.match(regexText).length;
     el.innerHTML = str.replace(regexText, replaceText);
-    
-    alert( "Tagged "+matchedCount+" entities!" );
+
+    $.bootstrapGrowl( "Tagged "+matchedCount+" entities!" );
 }
+
 function removeEmptyNodes( node ) {
     if (node.hasChildNodes()) {
         var children = node.childNodes;
@@ -108,16 +110,16 @@
 function removeTagTitle( range, container ) {
     saveUndoText();
     range.deleteContents();
-    
+
     lastAddTag = $('#RemoveTitletagType').val();
-    
+
     var stringtemp = container.innerHTML;
-    
+
     if ( $('#RemoveTitletagName').val() == "" ) {
         var regexText="<"+lastAddTag+">〈(.*?)〉</"+lastAddTag+">";
         var replaceText="";
         stringtemp = stringtemp.replace(new RegExp(regexText, "g"), replaceText);
-        
+
         var regexText="<"+lastAddTag+">(.*?)</"+lastAddTag+">";
         var replaceText="$1";
         stringtemp = stringtemp.replace(new RegExp(regexText, "g"), replaceText);
@@ -125,26 +127,26 @@
         var regexText="<"+lastAddTag+">〈"+$('#RemoveTitletagName').val()+"〉</"+lastAddTag+">";
         var replaceText="";
         stringtemp = stringtemp.replace(new RegExp(regexText, "g"), replaceText);
-        
+
         var regexText="<"+lastAddTag+">("+$('#RemoveTitletagName').val()+")</"+lastAddTag+">";
         var replaceText="$1";
         stringtemp = stringtemp.replace(new RegExp(regexText, "g"), replaceText);
     }
-    
+
     var newdiv = document.createElement("aaaa");
     newdiv.innerHTML = stringtemp;
     range.insertNode(newdiv);
-    
+
     var el = document.getElementById("editable-area");
-    
+
     var regexText=/<aaaa>/gi;
     var replaceText='';
     el.innerHTML = el.innerHTML.replace(regexText, replaceText);
-    
+
     var regexText=/<\/aaaa>/gi;
     var replaceText='';
     el.innerHTML = el.innerHTML.replace(regexText, replaceText);
-    
+
     $('.tagItemDivClass').remove();
 }
 
@@ -154,7 +156,7 @@
     saveUndoText();
 
     var el = document.getElementById("editable-area");
-    
+
     lastAddTag = $('#TitletagType').val();
     var tag = "<"+$('#TitletagType').val()+">〈"+$('#TitletagName').val()+"〉</"+$('#TitletagType').val()+">";
 
@@ -165,21 +167,21 @@
     var regexText=/<br>/g;
     var replaceText="<br>"+tag;
     stringtemp = stringtemp.replace(regexText, replaceText);
-  
+
     var newdiv = document.createElement("aaaa");
     newdiv.innerHTML = tag+stringtemp;
 
     range.insertNode(newdiv);
-   
+
 
     var regexText=/<aaaa>/gi;
     var replaceText='';
     el.innerHTML = el.innerHTML.replace(regexText, replaceText);
-    
+
     var regexText=/<\/aaaa>/gi;
     var replaceText='';
     el.innerHTML = el.innerHTML.replace(regexText, replaceText);
-    
+
     $('.tagItemDivClass').remove();
 
     removeEmptyNodes(el);   // removing self-closing tags
@@ -188,20 +190,20 @@
 
 function cleanUpTextArea() {
     var el = document.getElementById("editable-area");
-    
+
     var regexText=/<div>/gi;
     var replaceText='<br>';
     el.innerHTML = el.innerHTML.replace(regexText, replaceText);
-    
+
     var regexText=/<\/div>/gi;
     var replaceText='';
     el.innerHTML = el.innerHTML.replace(regexText, replaceText);
-    
-    
+
+
     var regexText=/<span style="(.*?)">/gi;
     var replaceText='';
     el.innerHTML = el.innerHTML.replace(regexText, replaceText);
-    
+
     var regexText=/<\/span>/gi;
     var replaceText='';
     el.innerHTML = el.innerHTML.replace(regexText, replaceText);
@@ -224,11 +226,57 @@
 function saveUndoText() {
     var el = document.getElementById("editable-area");
     //stringBeforeChange = el.innerHTML;
-    stringBeforeChangeStack.push(el.innerHTML); 
+    stringBeforeChangeStack.push(el.innerHTML);
     var el = document.getElementById("buttonUndo");
     el.disabled = false;
 }
 
+var EditingMode = "tagging";
+
+function switchToEditingMode(ele, new_mode){
+
+  if(EditingMode === new_mode) return;
+
+  EditingMode = new_mode;
+
+  saveUndoText();
+  document.getElementById("editable-area").contentEditable = true;
+
+  // disable/close functions
+  $("button").attr("disabled", true);
+  $("#editTextId").attr("disabled", false);
+  $("#popups").css("display","none"); // close the popup windows
+  $("input").attr('disabled', true); // disable input
+  // clean editable-area
+  $('.questionMarkClass').remove();
+  $('.tagItemDivClass').remove();
+
+  $('#smart-regex-area').css("display","none");
+  $('#tag-function-area').css("display","none");
+
+  $('#editable-area-wraper').parent().toggleClass("EditingMode");
+}
+
+function switchToTaggingMode(ele, new_mode){
+
+  if(EditingMode === new_mode) return;
+
+  EditingMode = new_mode;
+
+  document.getElementById("editable-area").contentEditable = false;
+  cleanUpTextArea();
+  $("button").attr("disabled", false);
+  $("#popups").css("display","block"); // open the popup windows
+  $("input").attr('disabled', false); // enable input
+  $("#editTextId").html("Edit text");
+
+  $('#smart-regex-area').css("display","block");
+  $('#tag-function-area').css("display","block");
+
+  $('#editable-area-wraper').parent().toggleClass("EditingMode");
+
+}
+/*
 function editText() {
     var el = document.getElementById("editable-area");
     if ( $("#editTextId").html() == "Edit text" ) {
@@ -244,7 +292,7 @@
         // clean editable-area
         $('.questionMarkClass').remove();
         $('.tagItemDivClass').remove();
-        
+
         $("#editTextId").html("Edit completed!");
     } else {
         // --- not editing mode ---
@@ -253,99 +301,110 @@
         $("button").attr("disabled", false);
         $("#popups").css("display","block"); // open the popup windows
         $("input").attr('disabled', false); // enable input
-        $("#editTextId").html("Edit text"); 
+        $("#editTextId").html("Edit text");
     }
 }
+*/
 
+var removeTagEngName;
 
 function removeTagNewDiv( eventObject, tag, tagObject ) {
+
     saveUndoText();
 
+    removeTagEngName = tag;
+
     var newdiv = document.createElement("div");
-    //$(newdiv).id = "questionMarkId";    
+    //$(newdiv).id = "questionMarkId";
     $(newdiv).attr("class", "questionMarkClass");
 
-    
     // set z-index to 3 to bring popup tag windwo to front
-    newdiv.style.cssText = 'top:'+eventObject.pageY+'; left:'+eventObject.pageX+';';
-    
+
+    var pageY = eventObject.pageY,
+        topPosi = pageY + ( (window.innerHeight - pageY < 145 ) ? -140 : 0) - 55;
+
+    newdiv.style.cssText = 'top:'+ topPosi + '; left:'+ (eventObject.pageX - 10) +';height:140px';
+
     // find tag displaying name by tagName then showing in the innerHTML
-    
+
     var tag_name = getTagNameByTag(tag);
     // newdiv.innerHTML = "Tag: "+tag_name+"<br>Value: "+tagObject.text()+"<br>";
 
-    // TODO maybe also shown tag itself? 
-    newdiv.innerHTML = "Tag: "+tag_name+"<br>Value: "+tagObject.text()+"<br>";
-    
+    // TODO maybe also shown tag itself?
+    newdiv.innerHTML = "Tag: "+tag_name+"<span class='removeTagText'>Value: "+tagObject.text()
+                     + "</span>";
+
+    var newbutton = $('<button class="btn btn-primary">Remove this</button>').mouseup(onRemoveThisTag);
+    newbutton.appendTo(newdiv);
 
+    var newbutton = $('<button class="btn btn-default">Remove this(with line break)</button>').mouseup(onRemoveThisTag);
+    newbutton.appendTo(newdiv);
+    $('<br>').appendTo(newdiv);
+
+    var newbutton = $('<button class="btn btn-primary">Remove all</button>').mouseup(onRemoveAllTag);
+
+    newbutton.appendTo(newdiv);
 
-    var newbutton = $('<button class="btn btn-default">Remove this</button>').mouseup(function (e2) {
-        var textKeep = $(this).parent().parent().html();
-        var regexText=/<div(.*?)<\/div>/g;
-        var replaceText="";
-        textKeep = textKeep.replace(regexText, replaceText);
-    
-        $(this).parent().parent().replaceWith( textKeep );
-    });
+    var newbutton = $('<button class="btn btn-default">Remove all(with line break)</button>').mouseup(onRemoveAllTag);
     newbutton.appendTo(newdiv);
-    
-    var newbutton = $('<button class="btn btn-default">Remove this(with line break)</button>').mouseup(function (e2) {
-        var textKeep = $(this).parent().parent().html();
-        var regexText=/<div(.*?)<\/div>/g;
-        var replaceText="";
-        textKeep = textKeep.replace(regexText, replaceText);
-    
+
+    tagObject.append(newdiv);
+
+}
+
+function onRemoveThisTag(e) {
+
+    var isWithBR = (e.target.innerText.indexOf("with line break") > 0);
+
+    var textKeep = $(this).parent().parent().html();
+    var regexText=/<div(.*?)<\/div>/g;
+    var replaceText="";
+    textKeep = textKeep.replace(regexText, replaceText);
+
+    if(isWithBR){
+
         var newLineBefore = $(this).parent().parent().prev();
         if ( newLineBefore.prop("tagName") == "BR" ) {
             $(this).parent().parent().prev().replaceWith( );
         }
-        $(this).parent().parent().replaceWith( textKeep );
-    });
-    newbutton.appendTo(newdiv);
-    
-    var newbutton = $('<button class="btn btn-default">Remove all</button>').mouseup(function (e2) {
-        var textKeep = $(this).parent().parent().html();
-        var regexText=/<div(.*?)<\/div>/g;
-        var replaceText="";
-        textKeep = textKeep.replace(regexText, replaceText);
-    
+    }
+
+    $(this).parent().parent().replaceWith( textKeep );
+}
+
+function onRemoveAllTag(e) {
+
+    var isWithBR = (e.target.innerText.indexOf("with line break") > 0);
+
+    var textKeep = $(this).parent().parent().html();
+    var regexText=/<div(.*?)<\/div>/g;
+    var replaceText="";
+    textKeep = textKeep.replace(regexText, replaceText);
+
+    if(isWithBR){
+        $(this).parent().remove();
+    }
+    else {
         $(this).parent().parent().replaceWith( textKeep );
-        
-        var el = document.getElementById("editable-area");
-        var regexText=new RegExp("<"+tag+">("+textKeep+")</"+tag+">", "g");
-        var replaceText="$1";
-        var str="" + el.innerHTML;
-        
-        if ( str.match(regexText)==null ) {
-            alert( "Removed 1 entity!" );
-        } else {
-            alert( "Removed "+(parseInt(str.match(regexText).length)+1)+" entities!" );
-        }
+    }
+
+    var regexPattern = "<"+removeTagEngName+">("+textKeep+")</"+removeTagEngName+">";
+
+    if(isWithBR){ regexPattern = "<br>" + regexPattern}
+
+    var el = document.getElementById("editable-area") ,
+        regexText=new RegExp(regexPattern, "g"),
+        replaceText="$1",
+        str= "" + el.innerHTML,
+        occurrences = (str.match(regexText) || []).length;
+
+    if(occurrences == 0){
+        $.bootstrapGrowl( (isWithBR) ? "No entity found" : "Removed 1 entity" );
+    }
+    else{
+        $.bootstrapGrowl( "Removed "+ (occurrences + 1) +" entities!" );
         el.innerHTML = str.replace(regexText, replaceText);
-    });
-    newbutton.appendTo(newdiv);
-    
-    var newbutton = $('<button class="btn btn-default">Remove all(with line break)</button>').mouseup(function (e2) {
-        var textKeep = $(this).parent().parent().html();
-        var regexText=/<div(.*?)<\/div>/g;
-        var replaceText="";
-        textKeep = textKeep.replace(regexText, replaceText);
-    
-        $(this).parent().remove();
-        
-        var el = document.getElementById("editable-area");
-        var regexText=new RegExp("<br><"+tag+">("+textKeep+")</"+tag+">", "g");
-        var replaceText="$1";
-        var str="" + el.innerHTML;
-        
-        alert( "Removed "+str.match(regexText).length+" entities!" );
-        el.innerHTML = str.replace(regexText, replaceText);
-    });
-    newbutton.appendTo(newdiv);
-    
-    tagObject.append(newdiv);
-
-
+    }
 }
 
 function saveText(section_id) {
@@ -357,18 +416,16 @@
         data : 'func=SaveFullText'+'&text='+encodeURIComponent(el.innerHTML)+'&filename='+section_id,
         // data : 'func=SaveFullText'+'&text='+el.innerHTML+'&filename='+section_id
         success: function (e) {
-            alert("Saved!");
+            $.bootstrapGrowl("Saved!");
         },
         error: function (e) {
-            alert("Haven't saved!");
+            $.bootstrapGrowl("Haven't saved!");
         }
     }).done(function(result) {
     });
-    
-    
-}
 
 
+}
 
 function preg_quote (str, delimiter) {
   // http://kevin.vanzonneveld.net
@@ -388,41 +445,40 @@
 
 function replaceRegex() {
     saveUndoText();
-    
+
     var startPage = $('#regexPageStart2').val();
     var endPage = $('#regexPageEnd2').val();
     var el = document.getElementById("editable-area");
     var str="" + el.innerHTML;
-    
+
     var regexText=document.getElementById("regexText").value;
     var replaceText=document.getElementById("replaceText").value;
     var str="" + el.innerHTML;
-    
+
     if ( startPage == "" ) {
-        alert( "Tagged "+str.match(new RegExp(regexText, "g")).length+" entities!" );
+        $.bootstrapGrowl( "Tagged "+str.match(new RegExp(regexText, "g")).length+" entities!" );
         el.innerHTML = str.replace(new RegExp(regexText, "g"), replaceText);
     } else {
         var regexText2="【<a([^<>]*?)>"+startPage+"</a>】(.*?)【<a([^<>]*?)>"+endPage+"</a>】";
         var partString = ""+str.match(new RegExp(regexText2, "g"));
-        alert(partString);
-        
-        alert( "Tagged "+partString.match(new RegExp(regexText, "g")).length+" entities!" );
+        $.bootstrapGrowl(partString);
+
+        $.bootstrapGrowl( "Tagged "+partString.match(new RegExp(regexText, "g")).length+" entities!" );
         var resultString = partString.replace(new RegExp(regexText, "g"), replaceText);
-        
+
         str="" + el.innerHTML;
         el.innerHTML = str.replace(new RegExp(regexText, "g"), resultString);
     }
-    
+
     //document.styleSheets[0].addRule("tag001", "color:green;")
 }
 
-
 //Tagging Items
 function getSelected() {
     if(window.getSelection) {   // all browsers, except IE before version 9
         return window.getSelection();
-    } else if (document.getSelection) { 
-        return document.getSelection(); 
+    } else if (document.getSelection) {
+        return document.getSelection();
     } else {    // IE
         var selection = document.selection && document.selection.createRange();
         if(selection.text) {
@@ -439,10 +495,10 @@
 
     saveUndoText();
     var el = document.getElementById("editable-area");
-  
+
     // TODO: bug? when stringValue contain already tag, it should be preserved
 
-    console.log(stringValue);
+    //console.log(stringValue);
 
 
     var regexText="("+String(stringValue)+")";
@@ -454,7 +510,7 @@
     var str="" + el.innerHTML;
 
     $('.tagItemDivClass').remove();
-    alert( "Tagged "+str.match(new RegExp(regexText, "g")).length+" entities!" );
+    $.bootstrapGrowl( "Tagged "+str.match(new RegExp(regexText, "g")).length+" entities!" );
     el.innerHTML = str.replace(new RegExp(regexText, "g"), replaceText);
 
     $('#loading').hide();
@@ -469,7 +525,7 @@
     range.insertNode(document.createTextNode("〈"+stringSelection+"〉"));
     var newdiv = document.createElement("br");
     range.insertNode(newdiv);
-    
+
     $('.tagItemDivClass').remove();
 }
 
@@ -479,8 +535,8 @@
     var regexText=/(○|】|^)(王|李|張|趙|劉|陳|楊|吳|黃|黄|朱|孫|郭|胡|呂|高|宋|徐|程|林|鄭|范|何|韓|曹|馬|許|田|馮|杜|周|曾|汪|蘇|董|方|蔡|梁|石|謝|賈|薛|彭|崔|唐|潘|鄧|史|錢|侯|魏|羅|葉|沈|孟|姚|傅|丁|章|蕭|蔣|盧|陸|袁|晁|譚|邵|歐陽|孔|詹|俞|尹|廖|閻|洪|夏|雷|葛|文|柳|陶|毛|丘|龔|蒲|邢|郝|龐|安|裴|折|施|游|金|鄒|湯|虞|嚴|鍾)([^○(舉人|縣人|歲貢|間任)]{1,3}|○[^○])(?=(○|$))/g;
     var replaceText="$1<br><person>$2$3</person>$4";
     var str="" + el.innerHTML;
-    
-    alert( "Tagged "+str.match(regexText).length+" entities!" );
+
+    $.bootstrapGrowl( "Tagged "+str.match(regexText).length+" entities!" );
     el.innerHTML = str.replace(regexText, replaceText);
 }
 
@@ -490,8 +546,8 @@
     var regexText="(○|】|^)("+$('#surname').val()+")([^○(舉人|縣人|歲貢|間任)]{1,3}|○[^○])(?=(○|$))";
     var replaceText="$1<br><person>$2$3</person>$4";
     var str="" + el.innerHTML;
-    
-    alert( "Tagged "+str.match(new RegExp(regexText, "g")).length+" entities!" );
+
+    $.bootstrapGrowl( "Tagged "+str.match(new RegExp(regexText, "g")).length+" entities!" );
     el.innerHTML = str.replace(new RegExp(regexText, "g"), replaceText);
 }
 
@@ -503,8 +559,8 @@
     var regexText=/(○)([^○]{1,6})(○?)(人)/g;
     var replaceText="$1<biog_addr>$2</biog_addr>$3$4";
     el.innerHTML = str.replace(regexText, replaceText);
-    
-    alert( "Tagged "+str.match(regexText).length+" entities!" );
+
+    $.bootstrapGrowl( "Tagged "+str.match(regexText).length+" entities!" );
 }
 
 function smartRegexNew() {
@@ -518,19 +574,35 @@
 
 
     $('#smartRegexPopUpAdd').attr("disabled", false);
-    $('#smartRegexPopUpEdit').attr("disabled", "disabled");
-    $('#smartRegexPopUpDel').attr("disabled", "disabled");
-    $('#smartRegexPopUpBack').attr("disabled", "disabled");
-    $('#smartRegexPopUpFor').attr("disabled", "disabled");
+    $('#smartRegexPopUpEdit').attr("disabled", false);
+    $('#smartRegexPopUpDel').attr("disabled", false);
+    $('#smartRegexPopUpBack').attr("disabled", false);
+    $('#smartRegexPopUpFor').attr("disabled", false);
+
+    if(popup_status == "none"){
+
+        $("#smartRegexPopUpName").val("no name");
+
+        replaceSmartAdd();
+
+        $('#smartRegexPopUpDiv').attr("editID", "regex_elem_"+regex_element_index);
+    }
 
 }
 
 function replaceSmartClose() {
+
+    if($("#smartRegexPopUpText").val().trim() == ''){
+
+        doReplaceSmartRemove();
+    }
+
     $('#smartRegexShowDiv > span').css("border","1px solid black");
     $('#smartRegexPopUpDiv').css("display", "none");
     $("#smartRegexPopUpSelectWord").val("NULL");
     $("#smartRegexPopUpText").val("");
     $("#smartRegexPopUpName").val("");
+
 }
 
 function replaceSmartEdit(){
@@ -541,32 +613,39 @@
     $('#smartRegexShowDiv > #'+thisObject).attr("regexReplace", $("#smartRegexPopUpSelectTag").val());
     $('#smartRegexShowDiv > #'+thisObject).text($("#smartRegexPopUpName").val());  // smartRgextPopUpName.val() is the name of this regex
     // id should be the same as it was
-}   
+}
+
+function replaceSmartRemove() {
+
+    doReplaceSmartRemove();
 
-function replaceSmartDel() {
+    replaceSmartClose();
+}
+
+function doReplaceSmartRemove() {
+
     thisObject = $('#smartRegexPopUpDiv').attr("editID");
 
     $('#smartRegexShowDiv > #'+thisObject).remove();
 }
 
 function replaceSmartFor() {
-    thisObject = $('#smartRegexPopUpDiv').attr("editID");
-    //var wahaha = $('#'+thisObject).clone();
-    //var hahawa = $('#'+thisObject).next();
-    //$('#'+thisObject).remove();
-    //wahaha.insertAfter(hahawa);
-    $('#smartRegexShowDiv > #'+thisObject).insertAfter( $('#'+thisObject).next() );
+
+    var nowEleId = $('#smartRegexPopUpDiv').attr("editID");
+    var nowEle = $('#smartRegexShowDiv > #' + nowEleId );
+
+    nowEle.insertAfter(nowEle.next());
 }
 
 function replaceSmartBack() {
-    thisObject = $('#smartRegexPopUpDiv').attr("editID");
-    //var wahaha = $('#'+thisObject).clone();
-    //var hahawa = $('#'+thisObject).prev();
-    //$('#'+thisObject).remove();
-    //wahaha.insertBefore(hahawa);
-    $('#smartRegexShowDiv > #'+thisObject).insertBefore( $('#'+thisObject).prev() );
+
+    var nowEleId = $('#smartRegexPopUpDiv').attr("editID");
+    var nowEle = $('#smartRegexShowDiv > #' + nowEleId );
+
+    nowEle.insertBefore(nowEle.prev());
 }
 
+
 function replaceSmartAdd() {
     var newdiv = document.createElement("span");
     //newdiv.innerHTML = " "+$("#smartRegexPopUpName").val()+" ";
@@ -575,11 +654,9 @@
 
     $(newdiv).css("border", "1px solid black");
     $(newdiv).css("width", "100px");
-    
+
     $(newdiv).attr("class", "span_"+$("#smartRegexPopUpSelectTag").val());
 
-
-
     // id is the name from user's input, which dose not guarantee to be unique
     // id should be unique
     regex_element_index += 1;
@@ -588,10 +665,9 @@
     $(newdiv).attr("regexText", $("#smartRegexPopUpText").val());
     $(newdiv).attr("regexReplace", $("#smartRegexPopUpSelectTag").val());
 
-    
     $('#smartRegexShowDiv').append(newdiv);
-    
-    replaceSmartClose();
+
+    //replaceSmartClose();
 }
 
 $(document).keyup(function(e) {
@@ -607,19 +683,18 @@
     }
 });
 
+$(document).on("click", '#smartRegexShowDiv > span', function (e) {
 
-$(document).on("click", '#smartRegexShowDiv > span', function (e) {
-    
     $('#smartRegexPopUpDiv').css("display", "block");
-    
+
     $('#smartRegexPopUpDiv').attr("editID", $(this).attr("id"));
-    
+
     $('#smartRegexPopUpName').val($(this).text());
     // $('#smartRegexPopUpName').val($(this).html());
 
     $('#smartRegexPopUpText').val($(this).attr("regexText"));
     $('#smartRegexPopUpSelectTag').val($(this).attr("regexReplace"));
-    
+
     $('#smartRegexPopUpAdd').attr("disabled", "disabled");
     $('#smartRegexPopUpEdit').attr("disabled", false);
     $('#smartRegexPopUpDel').attr("disabled", false);
@@ -631,18 +706,19 @@
     var btn_state = $('#regex_generator').css('display');
     if (btn_state == "block") {
         genRegexWindowClose();
-    } else { 
+    } else {
         $('#regex_generator').css("display", "block");
         $("#gen_regex_window_open_id").text("Close Gen Regex");
     }
 }
+
 function genRegexWindowClose(){
     $('#regex_generator').css("display", "none");
     $("#gen_regex_window_open_id").text("Open Gen Regex");
 }
 
 function sharedStart_(array){
-    var A= array.concat().sort(), 
+    var A= array.concat().sort(),
     a1= A[0], a2= A[A.length-1], L= a1.length, i= 0;
     while(i<L && a1.charAt(i)=== a2.charAt(i)) i++;
     return a1.substring(0, i);
@@ -659,24 +735,24 @@
         if (_tag == tag) {
             name = _name;
         }
-    }   
+    }
 
     return name;
 }
 
 function genRegexAddToSmartRegex() {
     // append blocks of generated regex to smart regex
-  
+
     smartRegexEmpty();  // clear
-    
+
     var reg_obj = getSuggestedRegex();
-    console.log(reg_obj);
+    //console.log(reg_obj);
 
     for (var i = 0; i < reg_obj.length; i++) {
         if (reg_obj[i].txt != "") {
-            
+
             var newdiv = document.createElement("span");
-            
+
             $(newdiv).css("border", "1px solid black");
             $(newdiv).css("width", "100px");
 
@@ -685,14 +761,14 @@
                     $(newdiv).text("空白");
                 } else {
                     $(newdiv).text(reg_obj[i].txt);
-                } 
+                }
                 $(newdiv).attr("class", "span_NOTAG");
                 $(newdiv).attr("regexReplace","NOTAG");
             } else {
-                
+
                 var name = getTagNameByTag(reg_obj[i].tag);
                 $(newdiv).text(name+"名");
-                
+
                 $(newdiv).attr("class", "span_"+reg_obj[i].tag);
                 $(newdiv).attr("regexReplace", reg_obj[i].tag);
 
@@ -700,9 +776,9 @@
 
             regex_element_index += 1;
             $(newdiv).attr("id", "regex_elem_"+regex_element_index);
-            
+
             $(newdiv).attr("regexText", reg_obj[i].txt);
-            
+
             $('#smartRegexShowDiv').append(newdiv);
 
         }
@@ -718,7 +794,7 @@
         len1 = string1.length,
         len2 = string2.length,
         row, col;
-    
+
     for(row = 0; row <= len1; row++){
         table[row] = [];
         for(col = 0; col <= len2; col++){
@@ -747,7 +823,7 @@
 }
 
 function longestCommonSubstring(s1, s2) {
-   
+
     var start_idx = 0;
     var max_len = 0;
     for (var i = 0; i < s1.length; i++)
@@ -801,7 +877,7 @@
                 // find matching for text in each corresponding position
                 var texts = [p0[i].txt, p1[i].txt];
                 var common = longestCommonSubstring(p0[i].txt, p1[i].txt);
-                
+
                 /*
                 var reg_for_common = "[";
                 for (var i = 0; i < common.length; i++) {
@@ -815,7 +891,7 @@
         };
     }
 
-    
+
 }
 
 function getSuggestedRegex(){
@@ -834,13 +910,13 @@
         console.log("Debug: ");
         console.log(_selection);
         */
-        
+
         if (_selection.type == "Range") {
             // select words, not just click on text
             var anchor_node = _selection.anchorNode;
             var focus_node = _selection.focusNode;
             var sibling_node = anchor_node.nextElementSibling;
-            
+
 
             if (anchor_node && sibling_node && focus_node && container.innerHTML.indexOf( "br" ) == -1) {
                 // Chrome can work on this.
@@ -850,7 +926,7 @@
                 var seleted_div = document.createElement("div");
                 var seleted_obj = [];   // array for selected text as well as its tag if it has any
 
-                if (anchor_node == focus_node ) { 
+                if (anchor_node == focus_node ) {
                     // selected text in plain text
                     var text_all = anchor_node.textContent;
                     var text_ = text_all.substring(_selection.anchorOffset, _selection.focusOffset);
@@ -876,9 +952,9 @@
                     console.log(text_after);
                     */
                 }
-                
-                
-                
+
+
+
                 var generated_regex_plaintext = "";
                 // show generate regex window
                 $('#regex_generator').css("display", "block");
@@ -913,15 +989,15 @@
 
                     pattern_obj.shift();
                     pattern_obj.push(seleted_obj);
-                   
+
                     setSuggestedRegex(pattern_obj);
                     var generated_regex = getSuggestedRegex();
-                   
+
                     // get plaintext from generated_regex obj
                     for (var i = 0; i < generated_regex.length; i++) {
                         generated_regex_plaintext += generated_regex[i].txt;
                     }
-                    
+
 
                 }
                 //$('#generated_regex').text(generated_regex);
@@ -939,13 +1015,37 @@
             // TODO: click on tagged text case rather than select
             // If do this process, also need to consider between browers since not all of them support
             // and also need to modify pop_remove_tag_window
-        }       
+        }
     });
 
     $(add_gen_regex_button).text("Add to Gen Regex (developing...)");
-    tag_item_div.appendChild(add_gen_regex_button);    
+    tag_item_div.appendChild(add_gen_regex_button);
+}
+
+var tagMode = "default";
+
+function onTagModeChanged(ele){
+    tagMode = ele.value;
 }
 
+function startToTag(){
+
+    switch(tagMode){
+
+       case "default":
+          replaceSmartRun();
+          break;
+       case "with_line_break":
+          replaceSmartRunWithBr();
+          break;
+       case "space_within_block":
+          replaceSmartRunSpace();
+          break;
+      //  case "xxx" :
+      //     replaceSmartRunSpace() //Allow space between Group
+      //     break;
+    }
+}
 
 function smartRegexEmpty() {
     $('#smartRegexShowDiv').html("");
@@ -959,9 +1059,9 @@
     var replaceSmartRegexString = "";
     var replaceSmartReplaceString = "";
     var count=1;
-    
+
     saveUndoText();
-    
+
     // skip everything inside "【】", including "【】". // (【([^【】])*】) //(【.*】)
     replaceSmartRegexString += "(【[^【】]+(?!.*})】)*";
     replaceSmartReplaceString += "$"+count;
@@ -980,28 +1080,28 @@
         }
         count++;
     });
-        
-        
+
+
     var startPage = $('#regexPageStart').val();
     var endPage = $('#regexPageEnd').val();
     var el = document.getElementById("editable-area");
     var str="" + el.innerHTML;
-    
+
     // if there's no match || the it's a null object..
     if (str.match(new RegExp(replaceSmartRegexString, "g")) == null) {
-        alert( "Tagged 0 entity!" );
+        $.bootstrapGrowl( "Tagged 0 entity!" );
 
     } else if ( startPage == "" ) {
-        alert( "Tagged "+str.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
+        $.bootstrapGrowl( "Tagged "+str.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
         el.innerHTML = str.replace(new RegExp(replaceSmartRegexString, "g"), replaceSmartReplaceString);
     } else {
         var regexText="【<a([^<>]*?)>"+startPage+"</a>】(.*?)【<a([^<>]*?)>"+endPage+"</a>】";
         var partString = ""+str.match(new RegExp(regexText, "g"));
-        alert(partString);
-        
-        alert( "Tagged "+partString.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
+        $.bootstrapGrowl(partString);
+
+        $.bootstrapGrowl( "Tagged "+partString.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
         var resultString = partString.replace(new RegExp(replaceSmartRegexString, "g"), replaceSmartReplaceString);
-        
+
         str="" + el.innerHTML;
         el.innerHTML = str.replace(new RegExp(regexText, "g"), resultString);
     }
@@ -1017,15 +1117,15 @@
     var replaceSmartRegexString = "";
     var replaceSmartReplaceString = "";
     var count=1;
-    
+
     saveUndoText();
-    
+
     // skip everything inside "【】", including "【】".
     replaceSmartRegexString += "(【[^【】]+(?!.*})】)*";
     replaceSmartReplaceString += "$"+count;
     count ++;
     // ---
- 
+
     $('#smartRegexShowDiv').children('span').each(function () {
         replaceSmartRegexString += "(" + $(this).attr("regexText") + ")";
         if ( $(this).attr("regexReplace") == "notag" || $(this).attr("regexReplace") == "NOTAG" ) {
@@ -1037,29 +1137,29 @@
         }
         count++;
     });
-        
-        
+
+
     var startPage = $('#regexPageStart').val();
     var endPage = $('#regexPageEnd').val();
     var el = document.getElementById("editable-area");
     var str="" + el.innerHTML;
-    
+
     // if there's no match || the it's a null object..
     if (str.match(new RegExp(replaceSmartRegexString, "g")) == null) {
-        alert( "Tagged 0 entity!" );
+        $.bootstrapGrowl( "Tagged 0 entity!" );
 
     } else if ( startPage == "" ) {
-        alert( "Tagged "+str.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
+        $.bootstrapGrowl( "Tagged "+str.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
 
         el.innerHTML = str.replace(new RegExp(replaceSmartRegexString, "g"), replaceSmartReplaceString);
     } else {
         var regexText="【<a([^<>]*?)>"+startPage+"</a>】(.*?)【<a([^<>]*?)>"+endPage+"</a>】";
         var partString = ""+str.match(new RegExp(regexText, "g"));
-        alert(partString);
-        
-        alert( "Tagged "+partString.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
+        $.bootstrapGrowl(partString);
+
+        $.bootstrapGrowl( "Tagged "+partString.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
         var resultString = partString.replace(new RegExp(replaceSmartRegexString, "g"), replaceSmartReplaceString);
-        
+
         str="" + el.innerHTML;
         el.innerHTML = str.replace(new RegExp(regexText, "g"), resultString);
     }
@@ -1068,16 +1168,16 @@
 }
 
 function replaceSmartRunSpace() {
-    
+
     $("#loading").show();
 
     var replaceSmartRegexString = "";
     var replaceSmartReplaceString = "";
     var count=1;
     saveUndoText();
-    
+
     $('#smartRegexShowDiv').children('span').each(function () {
-        //alert($(this).attr("regexText"));
+        //$.bootstrapGrowl($(this).attr("regexText"));
         replaceSmartRegexString += "(" + $(this).attr("regexText") + ")(○*)";
         if ( $(this).attr("regexReplace") == "notag" || $(this).attr("regexReplace") == "NOTAG") {
             replaceSmartReplaceString += "$" + count;
@@ -1090,39 +1190,39 @@
         replaceSmartReplaceString += "$" + count;
         count++;
     });
-    
+
     var startPage = $('#regexPageStart').val();
     var endPage = $('#regexPageEnd').val();
     var el = document.getElementById("editable-area");
     var str="" + el.innerHTML;
-    
+
     // if there's no match || the it's a null object..
     if (str.match(new RegExp(replaceSmartRegexString, "g")) == null) {
-        alert( "Tagged 0 entity!" );
+        $.bootstrapGrowl( "Tagged 0 entity!" );
 
     } else if ( startPage == "" ) {
-        alert( "Tagged "+str.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
+        $.bootstrapGrowl( "Tagged "+str.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
         el.innerHTML = str.replace(new RegExp(replaceSmartRegexString, "g"), replaceSmartReplaceString);
     } else {
         var regexText="【<a([^<>]*?)>"+startPage+"</a>】(.*?)【<a([^<>]*?)>"+endPage+"</a>】";
         var partString = ""+str.match(new RegExp(regexText, "g"));
-        alert(partString);
-        
-        alert( "Tagged "+partString.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
+        $.bootstrapGrowl(partString);
+
+        $.bootstrapGrowl( "Tagged "+partString.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
         var resultString = partString.replace(new RegExp(replaceSmartRegexString, "g"), replaceSmartReplaceString);
-        
+
         str="" + el.innerHTML;
         el.innerHTML = str.replace(new RegExp(regexText, "g"), resultString);
     }
-    
-    //alert( "Tagged "+str.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
+
+    //$.bootstrapGrowl( "Tagged "+str.match(new RegExp(replaceSmartRegexString, "g")).length+" entities!" );
     //el.innerHTML = str.replace(new RegExp(replaceSmartRegexString, "g"), replaceSmartReplaceString);
 
     $("#loading").hide();
 }
 
 function smartRegexSave(topic_id) {
-    console.log("topic_id"+topic_id);
+    //console.log("topic_id"+topic_id);
 
     var today = new Date();
     var minute = today.getMinutes();
@@ -1133,10 +1233,10 @@
 
     if(dd<10) {
         dd='0'+dd
-    } 
+    }
     if(mm<10) {
         mm='0'+mm
-    } 
+    }
     if (hour<10) {
         hour='0'+hour;
     }
@@ -1150,13 +1250,13 @@
 
 
     if (name!=null && name != ''){
-        
-        // the name not allowed to contain " ", "(", ")" 
+
+        // the name not allowed to contain " ", "(", ")"
         if (name.indexOf(' ') >= 0 || name.indexOf('(') >= 0 || name.indexOf(')') >= 0) {
 
-            alert("Save Regex Failed.\nPlease don't use space or '(' or ')' in the name. Consider to use '-' or '_' instead. ");
+            $.bootstrapGrowl("Save Regex Failed.\nPlease don't use space or '(' or ')' in the name. Consider to use '-' or '_' instead. ");
             return;
-        } 
+        }
 
         $.ajax({
             type : 'POST',
@@ -1164,17 +1264,17 @@
             async : false,
             data : 'func=SmartRegexSave'+'&text='+encodeURIComponent($('#smartRegexShowDiv').html())+'&filename='+name+'&topic_id='+topic_id,
             error: function (result) {
-                alert("Error");
+                $.bootstrapGrowl("Error");
             },
             success: function (result) {
                 var obj = jQuery.parseJSON(result);
 
                 if (obj == "ErrorDB") {
-                    alert("Error when saving to database!!");
+                    $.bootstrapGrowl("Error when saving to database!!");
 
                 } else if (obj == "ForceSave") {
                     var retVal = confirm("Danger! You will over write the previous regex file. Do you want to proceed?");
-                    
+
                     if( retVal == true ){
                         // update regex file
                         $.ajax({
@@ -1183,29 +1283,31 @@
                             async : false,
                             data : 'func=SmartRegexSave'+'&text='+encodeURIComponent($('#smartRegexShowDiv').html())+'&filename='+name+'&topic_id='+topic_id+'&forcesave=1',
                             error: function (result) {
-                                alert("Error");
+                                $.bootstrapGrowl("Error");
                             },
                             success: function (result) {
-                                alert("Update regex file.");
+                                $.bootstrapGrowl("Update regex file.");
                             }
                         });
                     }else{
-                        alert("You have not saved the regex file.");
+                        $.bootstrapGrowl("You have not saved the regex file.");
                     }
 
                 } else {
-                    alert("Saved!");
+                    $.bootstrapGrowl("Saved!");
                 }
             }
         }).done(function(result) {
         });
     } else {
-        alert("You haven't saved it.");
+        $.bootstrapGrowl("You haven't saved it.");
     }
 }
 
 function smartRegexLoad(topic_id) {
+
     $('#load_regex_div').html("");
+
     var popup_status = $('#load_regex_div').css("display");
     if (popup_status == "block") {
         $('#load_regex_div').css("display", "none");
@@ -1215,9 +1317,9 @@
 
     var newselect = document.createElement("select");
     newselect.id = "loadRegexSelect";
-            
+
     $.ajax({
-        type: 'POST', 
+        type: 'POST',
         url: './TaggingText',
         dataType: 'json',
         data: "func=SmartRegexLoad&topic_id="+topic_id,
@@ -1227,17 +1329,17 @@
                 // index is the filename (without '.txt')
                 // element is the content in the file
                 newselect.innerHTML += "<option value=\""+index+"\">"+index+"</option>\n";
-                //alert(index);
-                //alert(element);
+                //$.bootstrapGrowl(index);
+                //$.bootstrapGrowl(element);
                 var newdiv = document.createElement("div");
                 $(newdiv).css("display", "none");
                 $(newdiv).html(element);
-                
+
                 $(newdiv).attr("id", "div_"+index);
                 $('#load_regex_div').append(newdiv);
             });
-            
-            
+
+
         },
         error: function (data) {
             console.log("SmartRegexLoad fails");
@@ -1247,7 +1349,7 @@
 
     /*
     $.ajax({
-        type: 'POST', 
+        type: 'POST',
         url: '../models/_extractapp_func.php',
         dataType: 'json',
         data: "func=SmartRegexLoad",
@@ -1255,15 +1357,15 @@
         success: function (data) {
             $.each(data, function(index, element) {
                 newselect.innerHTML += "<option value=\""+index+"\">"+index+"</option>\n";
-                //alert(index);
-                //alert(element);
+                //$.bootstrapGrowl(index);
+                //$.bootstrapGrowl(element);
                 var newdiv = document.createElement("div");
                 $(newdiv).css("display", "none");
                 $(newdiv).html(element);
                 $(newdiv).attr("id", "div_"+index);
                 $('#load_regex_div').append(newdiv);
             });
-            
+
         },
         error: function (data) {
             console.log("SmartRegexLoad fails");
@@ -1271,18 +1373,29 @@
 
     });
     */
-    
+
+    var loadBtn = document.createElement("button");
+    $(loadBtn).html("Load");
+    $(loadBtn).addClass("btn btn-sm btn-info");
+    $(loadBtn).attr("onclick", "loadRegexAdd()");
+
+    var closeBtn = document.createElement("button");
+    $(closeBtn).html('<span aria-hidden=\"true\">×</span>');
+    $(closeBtn).addClass("btn btn-xs btn-default close-btn");
+    $(closeBtn).attr("onclick", "$('#load_regex_div').css(\"display\", \"none\");");
+
+    var emptyRow = document.createElement("div");
+    $(emptyRow).addClass("emptyRow");
+
+    var emptyRow2 = document.createElement("div");
+    $(emptyRow2).addClass("emptyRow");
+
+    emptyRow2.append(loadBtn);
+
+    $('#load_regex_div').append(closeBtn);
+    $('#load_regex_div').append(emptyRow);
     $('#load_regex_div').append(newselect);
-    var newbutton = document.createElement("button");
-    $(newbutton).html("Load");
-    $(newbutton).addClass("btn btn-info");
-    $(newbutton).attr("onclick", "loadRegexAdd()");
-    $('#load_regex_div').append(newbutton);
-    var newbutton = document.createElement("button");
-    $(newbutton).html("Close");
-    $(newbutton).addClass("btn btn-default");
-    $(newbutton).attr("onclick", "$('#load_regex_div').css(\"display\", \"none\");");
-    $('#load_regex_div').append(newbutton);
+    $('#load_regex_div').append(emptyRow2);
 }
 
 var RegexLoadedName = "";
@@ -1296,7 +1409,7 @@
 
     // get the largest regex element index in the regex file
     // for all children (span) in #smartRegexShowDiv, find MAX(id)
-    var regex_elem = $('#smartRegexShowDiv').children();   
+    var regex_elem = $('#smartRegexShowDiv').children();
     var max_id = 0;
     for (var i = 0; i < regex_elem.length; i++) {
         var r_id = parseInt(regex_elem[i].id.slice(11));    // cut the first 11 char out: "regex_elem_"
@@ -1317,7 +1430,7 @@
         // TODO: if this is clicked...
         $(this).css("border","1px solid black");
     });
-    
+
     /*
     // TODO: click
     $("#smartRegexShowDiv > span").click( function() {
@@ -1355,15 +1468,15 @@
         type : 'POST',
         data : 'func=AddNewList'+'&text='+el.value,
         success: function (e) {
-            alert("Added!");
+            $.bootstrapGrowl("Added!");
             document.location.reload(true);
         },
         error: function (e) {
             console.log("error when add new list");
-            alert("Haven't added new list!!");
+            $.bootstrapGrowl("Haven't added new list!!");
         }
     }).done(function(result) {
-        
+
     });
 }
 
@@ -1375,15 +1488,15 @@
         type : 'POST',
         data : 'func=SaveWordlist'+'&text='+el.innerHTML+'&filename='+id,
         success: function (e) {
-            alert("Saved!");
+            $.bootstrapGrowl("Saved!");
         },
         error: function (e) {
-            alert("Haven't saved!");
+            $.bootstrapGrowl("Haven't saved!");
         }
     }).done(function(result) {
-        
+
     });
-    
+
 }
 
 function editWordlistText( id ) {
@@ -1403,7 +1516,7 @@
     var xhr = new XMLHttpRequest();
     xhr.onreadystatechange = process;
     xhr.open("POST", "../data/wordlist/"+id+".txt?t=" + Math.random(), true);
-    // TODO: should show the latest wordlist file. eg. id_timestamp.txt, rather than open the original id.txt file 
+    // TODO: should show the latest wordlist file. eg. id_timestamp.txt, rather than open the original id.txt file
 
 
     xhr.send();
@@ -1415,7 +1528,7 @@
             var regexText=/\n/g;
             var replaceText="<br>\n";
             el.innerHTML = str.replace(regexText, replaceText);
-            
+
             document.getElementById("button-area").innerHTML=
             "<form action=\"javascript:void(0);\"> \
                 <fieldset><legend>Edit:</legend> \
@@ -1440,18 +1553,18 @@
     form.setAttribute("method", "post");
     form.setAttribute("action", "./EditTaglist");
     form.setAttribute("target", "_blank");
-    
-    var hiddenField = document.createElement("input");      
+
+    var hiddenField = document.createElement("input");
     hiddenField.setAttribute("name", "topic_id");
     hiddenField.setAttribute("value", topic_id);
     form.appendChild(hiddenField);
-    
+
     if(navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
         document.body.appendChild(form);
         form.submit();
         document.body.removeChild(form);
     } else {
-        //form.submit(); // works under IE and Chrome, but not FF  
+        //form.submit(); // works under IE and Chrome, but not FF
         document.body.appendChild(form);
         form.submit();
         document.body.removeChild(form);
@@ -1460,6 +1573,4 @@
 
 
 // ============
-// 
-
-
+//