Browse Source

Merge pull request #374 from visuddhinanda:master

js 文本比对
Bhikkhu-Kosalla 5 years ago
parent
commit
5737665764

+ 2 - 1
app/commit/commit.css

@@ -18,7 +18,8 @@ del {
 	color: red;
 }
 ins {
-	color: green;
+	background-color: greenyellow;
+	text-decoration: unset;
 }
 
 .commit_head {

+ 33 - 6
app/commit/commit.js

@@ -54,7 +54,7 @@ function commit_render_channel_select() {
 	html += "<div>";
 	html += "<select id='dest_channel' onchange='dest_change(this)'>";
 	if (typeof _commit_data.dest == "undefined") {
-		let lastDest = localStorage.getItem("commit_src_" + _commit_data.src);
+		let lastDest = localStorage.getItem("commit_dest_" + _commit_data.dest);
 		if (typeof lastDest == "undefined") {
 			html += "<option value='' selected>请选择目标版本</option>";
 		} else {
@@ -108,6 +108,7 @@ function commit_preview_render() {
 	let html = "";
 	html += "<div class='commit_win_inner'>";
 	html += commit_render_head(2);
+	_commit_data.dest = $("#dest_channel").val();
 
 	if (
 		typeof _commit_data.src != "undefined" &&
@@ -166,6 +167,11 @@ function commit_preview_render() {
 function commit_compare_mode_change(obj) {
 	previewWin.show(commit_render_comp(parseInt($(obj).val())));
 }
+/*
+		{ id: 0, string: "自动" },
+		{ id: 1, string: "全选" },
+		{ id: 2, string: "全不选" },
+*/
 function commit_render_comp(mode) {
 	let html = "";
 	html += "<div class='commit_win_inner'>";
@@ -244,16 +250,18 @@ function commit_render_comp(mode) {
 							html += "<ins>" + iterator.translation[0].text + "</ins>";
 						} else {
 							if (iterator.translation[0].update_time > iterator.translation[1].update_time) {
-								html += "<del>" + iterator.translation[1].text + "</del><br>";
-								html += "<ins>" + iterator.translation[0].text + "</ins>";
+								html += commit_render_diff(iterator.translation[1].text, iterator.translation[0].text);
+								//html += "<del>" + iterator.translation[1].text + "</del><br>";
+								//html += "<ins>" + iterator.translation[0].text + "</ins>";
 							} else {
 								html += "[新]" + iterator.translation[1].text;
 							}
 						}
 						break;
 					case 1:
-						html += "<del>" + iterator.translation[1].text + "</del><br>";
-						html += "<ins>" + iterator.translation[0].text + "</ins>";
+						html += commit_render_diff(iterator.translation[1].text, iterator.translation[0].text);
+						//html += "<del>" + iterator.translation[1].text + "</del><br>";
+						//html += "<ins>" + iterator.translation[0].text + "</ins>";
 						break;
 					case 2:
 						html += iterator.translation[1].text;
@@ -267,12 +275,31 @@ function commit_render_comp(mode) {
 		sentIndex++;
 	}
 	if (textCount == 0) {
-		html += "译文全部相同,无需推送。";
+		html += "全部相同,无需推送。";
 	}
 	html += "</div>";
 	return html;
 }
 
+function commit_render_diff(str1, str2) {
+	let output = "";
+
+	const diff = Diff.diffChars(str1, str2);
+
+	diff.forEach((part) => {
+		// green for additions, red for deletions
+		// grey for common parts
+		if (part.added) {
+			output += "<ins>" + part.value + "</ins>";
+		} else if (part.removed) {
+			output += "<del>" + part.value + "</del>";
+		} else {
+			output += part.value;
+		}
+	});
+	return output;
+}
+
 function commit_sent_select(obj) {
 	let sent_id = $(obj).attr("sent_id");
 	for (let iterator of sentData) {

+ 30 - 0
app/commit/diff.html

@@ -0,0 +1,30 @@
+<html>
+	<body>
+		<pre id="display"></pre>
+<script src="../../node_modules/diff/dist/diff.js"></script>
+<script>
+const one = 'beep boop',
+    other = 'beep boob blah',
+    color = '';
+    
+let span = null;
+
+const diff = Diff.diffChars(one, other),
+    display = document.getElementById('display'),
+    fragment = document.createDocumentFragment();
+
+diff.forEach((part) => {
+  // green for additions, red for deletions
+  // grey for common parts
+  const color = part.added ? 'green' : part.removed ? 'red' : 'grey';
+  span = document.createElement('span');
+  span.style.color = color;
+  span.appendChild(document
+    .createTextNode(part.value));
+  fragment.appendChild(span);
+});
+
+display.appendChild(fragment);
+</script>
+	</body>
+</html>

+ 56 - 0
app/db/pali_text.php

@@ -0,0 +1,56 @@
+<?php
+require_once "../path.php";
+require_once "../share/function.php";
+require_once "../db/table.php";
+
+class PaliText extends Table
+{
+    function __construct($redis=false) {
+		parent::__construct(_FILE_DB_PALITEXT_, "pali_text", "", "",$redis);
+    }
+
+	public function getTitle($book,$para)
+	{
+		if (isset($book) && isset($para)) {
+			if($this->redis!==false){
+				$title = $this->redis->hGet("para_title://pali","{$book}-{$para}");
+				if($title!==FALSE){
+					return $title;
+				}
+			}
+			$title="";
+			$query = "select * from pali_text where book = ? and paragraph = ?";
+			$stmt = $this->dbh->prepare($query);
+			$stmt->execute(array($book,$para));
+			$result = $stmt->fetch(PDO::FETCH_ASSOC);
+			if ($result) {
+				if($result["level"]>0 && $result["level"]<8){
+					$title= $result["toc"];
+				}
+				else{
+					$query = "select * from pali_text where book = ? and paragraph = ?";
+					$stmt = $this->dbh->prepare($query);
+					$stmt->execute(array($book,$result["parent"]));
+					$result = $stmt->fetch(PDO::FETCH_ASSOC);
+					if ($result) {
+						$title= $result["toc"];
+					}
+					else{
+						$title= "";
+					}
+				}
+				
+			} else {
+				$title= "";
+			}
+			$output = $this->redis->hSet("para_title://pali","{$book}-{$para}",$title);
+			return $title;
+		} else {
+			$title= "";
+		}
+	}
+
+
+}
+
+?>

+ 2 - 0
app/db/table.php

@@ -4,6 +4,8 @@
 			  ->set($date)
 			  ->commit();
 		*/
+require_once "../redis/function.php";
+
 class Table
 {
     protected $dbh;

+ 3 - 3
app/lang/lang.php

@@ -132,11 +132,11 @@
 	</button>
 	<ul class="header-dropdown-content right-content" id="lang_list">
 		<li>
-			<!--<a onclick="setLang('my')">-->
-			<div class="nav_link disable">
+			<a onclick="setLang('my')">
+			<div class="nav_link">
 				မြန်မာ
 			</div>
-			<!--</a>-->
+			</a>
 		</li>
 		<li><a onclick="setLang('si')">
 				<div class="nav_link">

+ 2 - 0
app/pcdl/html_head.php

@@ -118,6 +118,8 @@ if (isset($_GET["language"])) {
 		<?php require_once '../public/load_lang_js.php'; ?>
 	</script>
 
+	<script src="../../node_modules/diff/dist/diff.js"></script>
+	
 	<style>
 		.list_with_head {
 			display: flex;

+ 2 - 0
app/search/paliword.js

@@ -179,6 +179,8 @@ function render_nav(result) {
 			html += "<li >" + (index + 1) + "</li> ";
 		}
 	}
+	html += "<li >上一页</li> ";
+	html += "<li >下一页</li> ";
 	html += "</ul>";
 	return html;
 }

+ 15 - 3
app/search/paliword_sc.php

@@ -7,6 +7,10 @@ require_once "../public/_pdo.php";
 require_once "../public/load_lang.php"; //语言文件
 require_once "../public/function.php";
 require_once "../search/word_function.php";
+require_once "../db/pali_text.php";
+
+$_redis = redis_connect();
+$_dbPaliText = new PaliText($_redis);
 
 _load_book_index();
 
@@ -38,6 +42,7 @@ if (isset($_GET["page"])) {
 }
 
 if (count($arrWordList) > 1) {
+	# 查询多个词
     PDO_Connect(_FILE_DB_PALITEXT_);
     # 首先精确匹配
     $words = implode(" ", $arrWordList);
@@ -46,7 +51,7 @@ if (count($arrWordList) > 1) {
 
     foreach ($Fetch1 as $key => $value) {
         # code...
-        $newRecode["title"] = "title";
+        $newRecode["title"] = $_dbPaliText->getTitle($value["book"], $value["paragraph"]);
         $newRecode["path"] = _get_para_path($value["book"], $value["paragraph"]);
         $newRecode["book"] = $value["book"];
         $newRecode["para"] = $value["paragraph"];
@@ -55,6 +60,8 @@ if (count($arrWordList) > 1) {
         $newRecode["wt"] = 0;
         $out_data[] = $newRecode;
     }
+	$result["time"][] = array("event" => "精确匹配结束", "time" => microtime(true)-$_start);
+	/*
     #然后查分散的
     $strQuery = "";
     foreach ($arrWordList as $oneword) {
@@ -67,7 +74,7 @@ if (count($arrWordList) > 1) {
 
     foreach ($Fetch2 as $key => $value) {
         # code...
-        $newRecode["title"] = "title";
+        $newRecode["title"] = $_dbPaliText->getTitle($value["book"], $value["paragraph"]);
         $newRecode["path"] = _get_para_path($value["book"], $value["paragraph"]);
         $newRecode["book"] = $value["book"];
         $newRecode["para"] = $value["paragraph"];
@@ -76,7 +83,10 @@ if (count($arrWordList) > 1) {
         $newRecode["wt"] = 0;
         $out_data[] = $newRecode;
     }
-    $result["data"] = $out_data;
+    
+	$result["time"][] = array("event" => "查分散的结束", "time" => microtime(true)-$_start);
+*/
+	$result["data"] = $out_data;
     echo json_encode($result, JSON_UNESCAPED_UNICODE);
     # 然后查特别不精确的
     exit;
@@ -194,9 +204,11 @@ $result["time"][] = array("event" => "准备查询", "time" => microtime(true) -
 $time_start = microtime_float();
 
 PDO_Connect(_FILE_DB_PALI_INDEX_);
+
 $query = "SELECT count(*) from (SELECT book FROM word WHERE \"wordindex\" in $strQueryWordId  $strQueryBookId group by book,paragraph) where 1 ";
 $result["record_count"] = PDO_FetchOne($query);
 $result["time"][] = array("event" => "查询记录数", "time" => microtime(true) - $_start);
+
 $query = "SELECT book,paragraph, wordindex, sum(weight) as wt FROM word WHERE \"wordindex\" in $strQueryWordId $strQueryBookId GROUP BY book,paragraph ORDER BY wt DESC LIMIT 0,20";
 $Fetch = PDO_FetchAll($query);
 $result["time"][] = array("event" => "查询结束", "time" => microtime(true) - $_start);

+ 3 - 3
app/studio/js/relation_list.json

@@ -28,7 +28,7 @@ var list_relation=[
     },
     {
         "id": "ASV",
-        "case": ".nom.",
+        "case": "",
         "note": "Active Subject Relation",
         "sys_name": "Sadda Pan Goun",
         "author": "Ven. Pandita Pariyatti Faculty ITBMU",
@@ -37,7 +37,7 @@ var list_relation=[
     },
     {
         "id": "ASV",
-        "case": ".nom.",
+        "case": "",
         "note": "施动者<主格> -> 动词<br>XX把...",
         "sys_name": "Sadda Pan Goun",
         "author": "Ven. Pandita Pariyatti Faculty ITBMU",
@@ -46,7 +46,7 @@ var list_relation=[
     },
     {
         "id": "ASV",
-        "case": ".nom.",
+        "case": "",
         "note": "vuttakattar -> kiriyā",
         "sys_name": "Sadda Pan Goun",
         "author": "Ven. Pandita Pariyatti Faculty ITBMU",

+ 3 - 3
app/sync/login.php

@@ -25,8 +25,6 @@ if(isset($_POST["userid"]) && isset($_POST["password"]) ){
 	if($user->check_password($_POST["userid"],$_POST["password"])){
 		if(isset($_POST["server"])){
 			#本地登录
-			setcookie ( "sync_userid" ,  $_POST["userid"] , 0 ,  "/" , "" ,  false , true );
-			setcookie ( "sync_server" ,  $_POST["server"] , 0 ,  "/" , "" ,  false , true );
 			#在远程主机验证用户身份
 			$phpFile = $_POST["server"]."/app/sync/login.php";
 			$client = new \GuzzleHttp\Client();
@@ -35,8 +33,10 @@ if(isset($_POST["userid"]) && isset($_POST["password"]) ){
 			$arrServerMsg = json_decode($serveMsg,true);
 			if($arrServerMsg["error"]==0){
 				#验证成功
+				setcookie ( "sync_userid" ,  $_POST["userid"] , 0 ,  "/" , "" ,  false , true );
+				setcookie ( "sync_server" ,  $_POST["server"] , 0 ,  "/" , "" ,  false , true );				
 				$redis->hset("sync://key",$_POST["userid"],$arrServerMsg["key"]);
-				$output["message"]="本机登录成功<br>服务器验证成功:msg:".$serveMsg."<br>";
+				$output["message"]="本机登录成功<br>服务器验证成功<br>";
 				$output["message"].="<a href='index.php'>开始同步</a>";
 			}
 			else{

+ 8 - 0
app/sync/sync.js

@@ -2,6 +2,7 @@ var sync_db_list = [
 	{ script: "sync/table_article.php", count: -1, finished: 0, enable: false },
 	{ script: "sync/table_term.php", count: -1, finished: 0, enable: false },
 	{ script: "sync/table_article_collect.php", count: -1, finished: 0, enable: false },
+	{ script: "sync/table_channel.php", count: -1, finished: 0, enable: false },
 	{ script: "sync/table_sentence.php", count: -1, finished: 0, enable: true },
 ];
 var isStop = false;
@@ -25,6 +26,7 @@ function sync_push() {
 function sync_stop() {
 	isStop = true;
 }
+var retryCount = 0;
 function sync_do_db(src, dest, time = 1) {
 	let size = 500;
 	while (sync_db_list[sync_curr_do_db].enable == false) {
@@ -86,6 +88,12 @@ function sync_do_db(src, dest, time = 1) {
 				if (isStop) {
 					return;
 				}
+				if (result.error > 0 && retryCount < 2) {
+					retryCount++;
+					sync_do_db(src, dest, time);
+					return;
+				}
+				retryCount = 0;
 				sync_db_list[sync_curr_do_db].finished += parseInt(result.src_row);
 				if (result.src_row >= size) {
 					//没弄完,接着弄

+ 3 - 5
app/sync/sync.php

@@ -77,7 +77,7 @@ $response = $client->request('POST', $localhost.'/app/'.$path,['verify' => false
 $strLocalData = (string)$response->getBody();
 $localData = json_decode($strLocalData,true);
 if($localData["error"]>0){
-	$message .= $localData["message"];
+	$message .="client 拉 id 列表 error:". $localData["message"];
 	$output["message"]=$message;
 	echo json_encode($output, JSON_UNESCAPED_UNICODE);
 	exit;
@@ -135,7 +135,7 @@ else{
 
 	$message .= "<div>";
 	if(count($insert_to_local)>0){
-		$message .=  "需要新增到本地".count($insert_to_local)."条记录 | ";
+		$message .=  "需要新增到目标机".count($insert_to_local)."条记录 | ";
 		
 		#提取数据
 		$idInServer = json_encode($insert_to_local, JSON_UNESCAPED_UNICODE);
@@ -159,8 +159,7 @@ else{
 
 	$message .= "<div>";
 	if(count($update_to_local)>0){
-		$message .=  "需要更新到本地".count($update_to_local)."条记录 | ";
-		/*
+		$message .=  "需要更新到目标机".count($update_to_local)."条记录 | ";
 		$idInServer = json_encode($update_to_local, JSON_UNESCAPED_UNICODE);
 		$response = $client->request('POST', $server.'/app/'.$path,['verify' => false,'form_params'=>['op'=>'get','id'=>"{$idInServer}","key"=>$sync_key,"userid"=>$_COOKIE["userid"]]]);
 		$serverData=(string)$response->getBody();
@@ -176,7 +175,6 @@ else{
 		else{
 			$message .= "数据提取错误 错误信息:{$arrData["message"]} ";
 		}
-		*/
 	}
 	$message .= "</div>";
 

+ 1 - 0
app/sync/table_article.php

@@ -9,6 +9,7 @@ $input = (object) [
     "table" =>  "article",
     "uuid" =>  "id",
     "sync_id" =>  ["id"],
+	"where"=>"",
     "modify_time" =>  "modify_time",
     "receive_time" =>  "receive_time",
     "insert" => [

+ 1 - 0
app/sync/table_article_collect.php

@@ -12,6 +12,7 @@ $input = (object) [
     "table" =>  "collect",
     "uuid" =>  "id",
     "sync_id" =>  ["id"],
+	"where"=>"",
     "modify_time" =>  "modify_time",
     "receive_time" =>  "receive_time",
     "insert" => [

+ 39 - 0
app/sync/table_channel.php

@@ -0,0 +1,39 @@
+<?php
+//header('Content-type: application/json; charset=utf8');
+
+require_once "../path.php";
+require_once "../sync/function.php";
+
+$input = (object) [
+    "database" =>  _FILE_DB_CHANNAL_,
+    "table" =>  "channal",
+    "uuid" =>  "id",
+    "sync_id" =>  ["id"],
+	"where"=>"",
+    "modify_time" =>  "modify_time",
+    "receive_time" =>  "receive_time",
+    "insert" => [
+        'id',
+		'owner',
+		'name',
+		'summary',
+		'status',
+		'lang',
+		'create_time',
+		'modify_time',
+		'receive_time'
+    ],
+    "update" =>  [
+		'owner',
+		'name',
+		'summary',
+		'status',
+		'lang',
+		'modify_time'
+    ]    
+];
+
+$result = do_sync($input);
+echo json_encode($result, JSON_UNESCAPED_UNICODE);
+
+?>

+ 2 - 0
app/sync/table_term.php

@@ -8,8 +8,10 @@ $input = (object) [
     "database" =>  _FILE_DB_TERM_,
     "table" =>  "term",
     "uuid" =>  "guid",
+    "sync_id" =>  ["pali","tag","channal","owner"],
     "modify_time" =>  "modify_time",
     "receive_time" =>  "receive_time",
+	"where"=>"",
     "insert" => [
         'guid',
 		'word',

+ 3 - 0
app/term/term.css

@@ -865,3 +865,6 @@ span.keybutton {
 	padding: 0.7rem;
 	word-break: break-word;
 }
+span.tran_sent {
+	display: block;
+}

+ 276 - 0
app/term/text_compare.html

@@ -0,0 +1,276 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<title>文本比较工具</title>
+		<style type="text/css">
+			* {
+				padding: 0px;
+				margin: 0px;
+			}
+			html,
+			body {
+				overflow-y: hidden;
+			}
+			.edit_div {
+				border: 1px solid #cccccc;
+				overflow: auto;
+				position: relative;
+			}
+			.edit_div textarea {
+				resize: none;
+				background: none repeat scroll 0 0 transparent;
+				border: 0 none;
+				width: 100%;
+				height: 200px;
+				overflow-y: scroll;
+				position: absolute;
+				left: 0px;
+				top: 0px;
+				z-index: 2;
+				font-size: 18px;
+				white-space: pre-wrap;
+				word-wrap: break-word;
+				word-break: break-all;
+			}
+			.edit_div pre {
+				overflow-y: scroll;
+				white-space: pre-wrap;
+				word-wrap: break-word;
+				word-break: break-all;
+				width: 100%;
+				height: 200px;
+				text-align: left;
+				color: #ffffff;
+				z-index: 1;
+				font-size: 18px;
+			}
+		</style>
+	</head>
+	<body>
+		<table style="width: 100%">
+			<tr>
+				<td style="width: 50%">
+					<div class="edit_div">
+						<pre id="edit_pre_1"></pre>
+						<textarea
+							id="edit_textarea_1"
+							onscroll="test1_scroll()"
+							oninput="textchange()"
+							onpropertychange="textchange()"
+						></textarea>
+					</div>
+				</td>
+				<td style="width: 50%">
+					<div class="edit_div">
+						<pre id="edit_pre_2"></pre>
+						<textarea
+							id="edit_textarea_2"
+							onscroll="test2_scroll()"
+							oninput="textchange()"
+							onpropertychange="textchange()"
+						></textarea>
+					</div>
+				</td>
+			</tr>
+		</table>
+		<script type="text/javascript">
+			function test1_scroll() {
+				document.getElementById("edit_pre_1").scrollTop = document.getElementById("edit_textarea_1").scrollTop;
+				document.getElementById("edit_pre_2").scrollTop = document.getElementById("edit_pre_1").scrollTop;
+				document.getElementById("edit_textarea_2").scrollTop = document.getElementById(
+					"edit_textarea_1"
+				).scrollTop;
+			}
+			function test2_scroll() {
+				document.getElementById("edit_pre_2").scrollTop = document.getElementById("edit_textarea_2").scrollTop;
+				document.getElementById("edit_pre_1").scrollTop = document.getElementById("edit_pre_2").scrollTop;
+				document.getElementById("edit_textarea_1").scrollTop = document.getElementById(
+					"edit_textarea_2"
+				).scrollTop;
+			}
+			function textchange() {
+				var op = eq({
+					value1: document.getElementById("edit_textarea_1").value,
+					value2: document.getElementById("edit_textarea_2").value,
+				});
+				document.getElementById("edit_pre_1").innerHTML = op.value1 + "\r\n";
+				document.getElementById("edit_pre_2").innerHTML = op.value2 + "\r\n";
+			}
+			function eq(op) {
+				if (!op) {
+					return op;
+				}
+				if (!op.value1_style) {
+					op.value1_style = "background-color:#FEC8C8;";
+				}
+				if (!op.value2_style) {
+					op.value2_style = "background-color:#FEC8C8;";
+				}
+				if (!op.eq_min) {
+					op.eq_min = 3;
+				}
+				if (!op.eq_index) {
+					op.eq_index = 5;
+				}
+				if (!op.value1 || !op.value2) {
+					return op;
+				}
+				var ps = {
+					v1_i: 0,
+					v1_new_value: "",
+					v2_i: 0,
+					v2_new_value: "",
+				};
+				while (ps.v1_i < op.value1.length && ps.v2_i < op.value2.length) {
+					if (op.value1[ps.v1_i] == op.value2[ps.v2_i]) {
+						ps.v1_new_value += op.value1[ps.v1_i].replace(/</g, "<").replace(">", ">");
+						ps.v2_new_value += op.value2[ps.v2_i].replace(/</g, "<").replace(">", ">");
+						ps.v1_i += 1;
+						ps.v2_i += 1;
+						if (ps.v1_i >= op.value1.length) {
+							ps.v2_new_value +=
+								"<span style='" +
+								op.value2_style +
+								"'>" +
+								op.value2.substr(ps.v2_i).replace(/</g, "<").replace(">", ">") +
+								"</span>";
+							break;
+						}
+						if (ps.v2_i >= op.value2.length) {
+							ps.v1_new_value +=
+								"<span style='" +
+								op.value1_style +
+								"'>" +
+								op.value1.substr(ps.v1_i).replace(/</g, "<").replace(">", ">") +
+								"</span>";
+							break;
+						}
+					} else {
+						ps.v1_index = ps.v1_i + 1;
+						ps.v1_eq_length = 0;
+						ps.v1_eq_max = 0;
+						ps.v1_start = ps.v1_i + 1;
+						while (ps.v1_index < op.value1.length) {
+							if (op.value1[ps.v1_index] == op.value2[ps.v2_i + ps.v1_eq_length]) {
+								ps.v1_eq_length += 1;
+							} else if (ps.v1_eq_length > 0) {
+								if (ps.v1_eq_max < ps.v1_eq_length) {
+									ps.v1_eq_max = ps.v1_eq_length;
+									ps.v1_start = ps.v1_index - ps.v1_eq_length;
+								}
+								ps.v1_eq_length = 0;
+								break; //只寻找最近的
+							}
+							ps.v1_index += 1;
+						}
+						if (ps.v1_eq_max < ps.v1_eq_length) {
+							ps.v1_eq_max = ps.v1_eq_length;
+							ps.v1_start = ps.v1_index - ps.v1_eq_length;
+						}
+
+						ps.v2_index = ps.v2_i + 1;
+						ps.v2_eq_length = 0;
+						ps.v2_eq_max = 0;
+						ps.v2_start = ps.v2_i + 1;
+						while (ps.v2_index < op.value2.length) {
+							if (op.value2[ps.v2_index] == op.value1[ps.v1_i + ps.v2_eq_length]) {
+								ps.v2_eq_length += 1;
+							} else if (ps.v2_eq_length > 0) {
+								if (ps.v2_eq_max < ps.v2_eq_length) {
+									ps.v2_eq_max = ps.v2_eq_length;
+									ps.v2_start = ps.v2_index - ps.v2_eq_length;
+								}
+								ps.v1_eq_length = 0;
+								break; //只寻找最近的
+							}
+							ps.v2_index += 1;
+						}
+						if (ps.v2_eq_max < ps.v2_eq_length) {
+							ps.v2_eq_max = ps.v2_eq_length;
+							ps.v2_start = ps.v2_index - ps.v2_eq_length;
+						}
+						if (ps.v1_eq_max < op.eq_min && ps.v1_start - ps.v1_i > op.eq_index) {
+							ps.v1_eq_max = 0;
+						}
+						if (ps.v2_eq_max < op.eq_min && ps.v2_start - ps.v2_i > op.eq_index) {
+							ps.v2_eq_max = 0;
+						}
+						if (ps.v1_eq_max == 0 && ps.v2_eq_max == 0) {
+							ps.v1_new_value +=
+								"<span style='" +
+								op.value1_style +
+								"'>" +
+								op.value1[ps.v1_i].replace(/</g, "<").replace(">", ">") +
+								"</span>";
+							ps.v2_new_value +=
+								"<span style='" +
+								op.value2_style +
+								"'>" +
+								op.value2[ps.v2_i].replace(/</g, "<").replace(">", ">") +
+								"</span>";
+							ps.v1_i += 1;
+							ps.v2_i += 1;
+
+							if (ps.v1_i >= op.value1.length) {
+								ps.v2_new_value +=
+									"<span style='" +
+									op.value2_style +
+									"'>" +
+									op.value2.substr(ps.v2_i).replace(/</g, "<").replace(">", ">") +
+									"</span>";
+								break;
+							}
+							if (ps.v2_i >= op.value2.length) {
+								ps.v1_new_value +=
+									"<span style='" +
+									op.value1_style +
+									"'>" +
+									op.value1.substr(ps.v1_i).replace(/</g, "<").replace(">", ">") +
+									"</span>";
+								break;
+							}
+						} else if (ps.v1_eq_max > ps.v2_eq_max) {
+							ps.v1_new_value +=
+								"<span style='" +
+								op.value1_style +
+								"'>" +
+								op.value1
+									.substr(ps.v1_i, ps.v1_start - ps.v1_i)
+									.replace(/</g, "<")
+									.replace(">", ">") +
+								"</span>";
+							ps.v1_i = ps.v1_start;
+						} else {
+							ps.v2_new_value +=
+								"<span style='" +
+								op.value2_style +
+								"'>" +
+								op.value2
+									.substr(ps.v2_i, ps.v2_start - ps.v2_i)
+									.replace(/</g, "<")
+									.replace(">", ">") +
+								"</span>";
+							ps.v2_i = ps.v2_start;
+						}
+					}
+				}
+				op.value1 = ps.v1_new_value;
+				op.value2 = ps.v2_new_value;
+				return op;
+			}
+			function settextheight() {
+				var heigth = document.documentElement.clientHeight - 6 + "px";
+				document.getElementById("edit_pre_1").style.height = heigth;
+				document.getElementById("edit_textarea_1").style.height = heigth;
+				document.getElementById("edit_pre_2").style.height = heigth;
+				document.getElementById("edit_textarea_2").style.height = heigth;
+			}
+			window.onload = function () {
+				settextheight();
+				window.onresize = function () {
+					settextheight();
+				};
+			};
+		</script>
+	</body>
+</html>

+ 1 - 1
app/usent/function.php

@@ -192,7 +192,7 @@ class Sent_DB
 					$sth->execute(array($data["text"],mb_strlen($data["text"],"UTF-8"),$data["editor"],$data["modify_time"],mTime(),$data["book"],$data["paragraph"],$data["begin"],$data["end"],$data["channal"]));
 				}
 			}
-			else{
+			else if(isset($arrData[0]["id"])){
 				$query = "UPDATE sentence SET text = ? , strlen = ? , editor=?, modify_time= ? ,receive_time = ?   where  id= ?  ";
 				$sth = $this->dbh_sent->prepare($query);
 				foreach ($arrData as $data) {

+ 5 - 0
package-lock.json

@@ -7,6 +7,11 @@
       "resolved": "https://registry.npmjs.org/at-js/-/at-js-1.2.12.tgz",
       "integrity": "sha1-X26O1gXopRmgXn0lMKSgKaxtPCU="
     },
+    "diff": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w=="
+    },
     "highcharts": {
       "version": "9.0.1",
       "resolved": "https://registry.npmjs.org/highcharts/-/highcharts-9.0.1.tgz",

+ 1 - 0
package.json

@@ -3,6 +3,7 @@
   "lockfileVersion": 1,
   "dependencies": {
     "at-js": "^1.2.12",
+    "diff": "^5.0.0",
     "highcharts": "^9.0.1",
     "marked": "^2.0.3",
     "tributejs": "^5.1.3"