Browse Source

Merge branch 'master' of https://gitee.com/bhikkhu-kosalla/mint

bhikkhu-kosalla-china 4 years ago
parent
commit
7881c084ec

+ 24 - 20
app/article/article.js

@@ -124,25 +124,11 @@ function render_article_list(article_list, collection_id) {
 		if (element.article == _articel_id) {
 			if (index > 0) {
 				const prev = article_list[index - 1];
-				prevArticle =
-					"<a href='../article/index.php?id=" +
-					prev.article +
-					display +
-					urlCollection +
-					"'>" +
-					prev.title +
-					"</a>";
+				prevArticle = "<a onclick=\"gotoArticle('" + prev.article + "')\">" + prev.title + "</a>";
 			}
 			if (index < article_list.length - 1) {
 				const next = article_list[index + 1];
-				nextArticle =
-					"<a href='../article/index.php?id=" +
-					next.article +
-					display +
-					urlCollection +
-					"'>" +
-					next.title +
-					"</a>";
+				nextArticle = "<a onclick=\"gotoArticle('" + next.article + "')\">" + next.title + "</a>";
 			}
 			$("#contents_nav_left").html(prevArticle);
 			$("#contents_nav_right").html(nextArticle);
@@ -151,11 +137,9 @@ function render_article_list(article_list, collection_id) {
 			"<li class='level_" +
 			element.level +
 			"'>" +
-			"<a href='../article/index.php?id=" +
+			"<a onclick=\"gotoArticle('" +
 			element.article +
-			display +
-			urlCollection +
-			"'>" +
+			"')\">" +
 			element.title +
 			"</a></li>";
 	}
@@ -196,5 +180,25 @@ function setMode(mode = "read") {
 	if (mode != "") {
 		url += "&mode=" + mode;
 	}
+	if (_direction != "") {
+		url += "&direction=" + _direction;
+	}
+	location.assign(url);
+}
+//跳转到另外一个文章
+function gotoArticle(articleId) {
+	let url = "../article/index.php?id=" + articleId;
+	if (_channal != "") {
+		url += "&channal=" + _channal;
+	}
+	if (_display != "") {
+		url += "&display=" + _display;
+	}
+	if (_mode != "") {
+		url += "&mode=" + _mode;
+	}
+	if (_direction != "") {
+		url += "&direction=" + _direction;
+	}
 	location.assign(url);
 }

+ 35 - 35
app/article/article_add_dlg.js

@@ -1,49 +1,49 @@
 var _article_add_dlg_div;
 function article_add_dlg_init(div) {
-  _article_add_dlg_div = div;
-  let html = "";
-  html += "<div id='article_add_dlg'>";
-  html += "<fieldset class='broder-1 broder-r'>";
-  html += "<legend>" + gLocal.gui.title + "</legend>";
-  html += "<input type='input' id='article_add_title' placeholder='" + gLocal.gui.input + gLocal.gui.title + "' />";
-  html += "</fieldset>";
-  html += "<div>";
-  html += "</div>";
-  html +=
-    "<div style='display:flex;justify-content: space-evenly;padding-top: 1em;'>";
-  html += "<button onclick='article_add_cancel()'>" + gLocal.gui.cancel + "</button>";
-  html += "<button onclick='article_add_new()'>" + gLocal.gui.new + "</button>";
-  html += "</div>";
-  html += "</div>";
+	_article_add_dlg_div = div;
+	let html = "";
+	html += "<div id='article_add_dlg'>";
+	html += "<fieldset class='broder-1 broder-r'>";
+	html += "<legend>" + gLocal.gui.title + "</legend>";
+	html += "<input type='input' id='article_add_title' placeholder='" + gLocal.gui.input + gLocal.gui.title + "' />";
+	html += "</fieldset>";
+	html += "<div>";
+	html += "</div>";
+	html += "<div style='display:flex;justify-content: space-evenly;padding-top: 1em;'>";
+	html += "<button onclick='article_add_cancel()'>" + gLocal.gui.cancel + "</button>";
+	html += "<button onclick='article_add_new()'>" + gLocal.gui.new + "</button>";
+	html += "</div>";
+	html += "</div>";
 
-  $("#" + div).append(html);
+	$("#" + div).append(html);
 }
 
 function article_add_dlg_show() {
-  $("#" + _article_add_dlg_div).show();
+	$("#" + _article_add_dlg_div).show();
 }
 function article_add_dlg_hide() {
-  $("#" + _article_add_dlg_div).hide();
+	$("#" + _article_add_dlg_div).hide();
 }
 function article_add_cancel() {
-  article_add_dlg_hide();
-  $("#article_add_title").val("");
+	article_add_dlg_hide();
+	$("#article_add_title").val("");
 }
 
 function article_add_new() {
-  $.post(
-    "../article/my_article_put.php",
-    {
-      title: $("#article_add_title").val(),
-    },
-    function (data) {
-      let error = JSON.parse(data);
-      if (error.status == 0) {
-        alert("ok");
-        article_add_cancel();
-      } else {
-        alert(error.message);
-      }
-    }
-  );
+	$.post(
+		"../article/my_article_put.php",
+		{
+			title: $("#article_add_title").val(),
+		},
+		function (data) {
+			let error = JSON.parse(data);
+			if (error.status == 0) {
+				alert("ok");
+				article_add_cancel();
+				window.location.reload();
+			} else {
+				alert(error.message);
+			}
+		}
+	);
 }

+ 44 - 45
app/article/collect_add_dlg.js

@@ -1,60 +1,59 @@
 var _collect_add_dlg_div;
 function collect_add_dlg_init(div) {
-  _collect_add_dlg_div = div;
-  let html = "";
-  html += "<div id='collect_add_dlg'>";
-  html += "<div >";
-  html += "<div >" + gLocal.gui.anthology + gLocal.gui.title + "</div>";
-  html += "<input type='input' id='collect_add_title' />";
-  html += "</div>";
-  html += "<div>";
-  html += "</div>";
-  html +=
-    "<div style='display:flex;justify-content: space-between;padding-top: 1em;'>";
-  html += "<div>";
-  html += "<select id='collect_add_dlg_status'>";
-  html += "<option value='1'>" + gLocal.gui.private + "</option>";
-  html += "<option value='2'>" + gLocal.gui.unlisted + "</option>";
-  html += "<option value='3'>" + gLocal.gui.public + "</option>";
-  html += "</select>";
+	_collect_add_dlg_div = div;
+	let html = "";
+	html += "<div id='collect_add_dlg'>";
+	html += "<div >";
+	html += "<div >" + gLocal.gui.anthology + gLocal.gui.title + "</div>";
+	html += "<input type='input' id='collect_add_title' />";
+	html += "</div>";
+	html += "<div>";
+	html += "</div>";
+	html += "<div style='display:flex;justify-content: space-between;padding-top: 1em;'>";
+	html += "<div>";
+	html += "<select id='collect_add_dlg_status'>";
+	html += "<option value='10'>" + gLocal.gui.private + "</option>";
+	html += "<option value='30'>" + gLocal.gui.public + "</option>";
+	html += "</select>";
 
-  html += "</div>";
-  html += "<div>";
-  html += "<button onclick='collect_add_cancel()'>" + gLocal.gui.cancel + "</button>";
-  html += "<button onclick='collect_add_new()'>" + gLocal.gui.new + "</button>";
-  html += "</div>";
-  html += "</div>";
-  html += "</div>";
+	html += "</div>";
+	html += "<div>";
+	html += "<button onclick='collect_add_cancel()'>" + gLocal.gui.cancel + "</button>";
+	html += "<button onclick='collect_add_new()'>" + gLocal.gui.new + "</button>";
+	html += "</div>";
+	html += "</div>";
+	html += "</div>";
 
-  $("#" + div).append(html);
+	$("#" + div).append(html);
 }
 
 function collect_add_dlg_show() {
-  $("#" + _collect_add_dlg_div).show();
+	$("#" + _collect_add_dlg_div).show();
 }
 function collect_add_dlg_hide() {
-  $("#" + _collect_add_dlg_div).hide();
+	$("#" + _collect_add_dlg_div).hide();
 }
 function collect_add_cancel() {
-  collect_add_dlg_hide();
-  $("#collect_add_title").val("");
+	collect_add_dlg_hide();
+	$("#collect_add_title").val("");
 }
 
 function collect_add_new() {
-  $.post(
-    "../article/my_collect_put.php",
-    {
-      title: $("#collect_add_title").val(),
-      status: $("#collect_add_dlg_status").val(),
-    },
-    function (data) {
-      let error = JSON.parse(data);
-      if (error.status == 0) {
-        alert("ok");
-        collect_add_cancel();
-      } else {
-        alert(error.message);
-      }
-    }
-  );
+	$.post(
+		"../article/my_collect_put.php",
+		{
+			title: $("#collect_add_title").val(),
+			status: $("#collect_add_dlg_status").val(),
+		},
+		function (data) {
+			let error = JSON.parse(data);
+			if (error.status == 0) {
+				alert("ok");
+				collect_add_cancel();
+				window.location.reload();
+			} else {
+				alert(error.message);
+			}
+		}
+	);
 }

+ 6 - 1
app/article/get.php

@@ -12,7 +12,12 @@ require_once "../article/function.php";
 
 if(isset($_GET["id"])){
 	//查询权限
-	$collectionId = $_GET["collection_id"];
+	if(isset($_GET["collection_id"])){
+		$collectionId = $_GET["collection_id"];
+	}
+	else{
+		$collectionId = "";
+	}
 	$redis = redis_connect();
 	$article = new Article($redis); 
 	$power = $article->getPower($_GET["id"],$collectionId);

+ 25 - 3
app/article/my_article.js

@@ -195,7 +195,13 @@ function my_article_edit(id) {
 					html += "<input type='hidden' name='tag' value='" + result.tag + "'/>";
 					html += "<input type='hidden' name='status' value='" + result.status + "'/>";
 
-					//html += "<input type='checkbox' name='import' />" + gLocal.gui.import + gLocal.gui.text;
+					html += "<div style='display:none;'>";
+					html +=
+						"<input type='checkbox' name='import' id='import_custom_book'  />" +
+						gLocal.gui.import +
+						gLocal.gui.text;
+					html += "</div>";
+
 					html += "<div>";
 					//html += "<div id='article_collect' vui='collect-dlg' ></div>"
 					html += "<div style='display:flex;'>";
@@ -207,8 +213,9 @@ function my_article_edit(id) {
 					html += "<span style='flex:1;'>" + gLocal.gui.status + "</span>";
 					html += '<span id="aritcle_status" style="flex:7;"></span>';
 					html += "</div>";
+					html += '<div style="width:100%;" >';
 					html +=
-						'<div style="display:none;width:100%;" ><span style="flex:3;margin: auto;">' +
+						'<span style="flex:3;margin: auto;">' +
 						gLocal.gui.language_select +
 						'</span>	<input id="article_lang_select"  style="flex:7;width:100%;" type="input" onchange="article_lang_change()"  placeholder="' +
 						gLocal.gui.input +
@@ -271,7 +278,21 @@ function article_preview() {
 	$("#preview_inner").html(note_init($("#article_content").val()));
 	note_refresh_new();
 }
-
+function my_article_custom_book() {
+	$content = $("#article_content").val();
+	if ($content == "") {
+		alert("内容不能为空");
+		return;
+	}
+	if ($content.indexOf("{{") >= 0) {
+		alert("不能包含句子模版");
+		return;
+	}
+	if (confirm("将此文档转换为自定义书模版吗?") == true) {
+		document.querySelector("#import_custom_book").checked = true;
+		my_article_save();
+	}
+}
 function my_article_save() {
 	$.ajax({
 		type: "POST", //方法类型
@@ -283,6 +304,7 @@ function my_article_save() {
 
 			if (result.status == 0) {
 				alert(gLocal.gui.saved + gLocal.gui.successful);
+				window.location.reload();
 			} else {
 				alert("error:" + result.message);
 			}

+ 11 - 1
app/article/my_article_edit.php

@@ -72,7 +72,7 @@ require_once '../studio/index_head.php';
 
 				<span class="icon_btn_div">
 					<span class="icon_btn_tip"><?php echo $_local->gui->back ;?></span>
-					<button id="icon_btn" type="button" class="icon_btn"  onclick="my_article_save()">
+					<button id="icon_btn" type="button" class="icon_btn" >
 						<a href="../article/my_article_index.php" >
 							<svg class="icon">
 								<use xlink:href="../studio/svg/icon.svg#return"></use>
@@ -92,7 +92,17 @@ require_once '../studio/index_head.php';
 
 				
 			</div>
+			
 			<div style="display:flex;">
+				<span class="icon_btn_div">
+					<span class="icon_btn_tip"><?php echo "自定义书" ;?></span>
+					<button id="edit_custom_book" type="button" class="icon_btn"  onclick="my_article_custom_book()">
+						<svg class="icon">
+							<use xlink:href="../studio/svg/icon.svg#convert"></use>
+						</svg>
+					</button>
+				</span>
+
 				<div id="article_collect" vui='collect-dlg' ></div>
 				<span class="icon_btn_div">
 					<span class="icon_btn_tip"><?php echo $_local->gui->scan_in_reader ;?></span>

+ 27 - 88
app/article/my_article_post.php

@@ -6,6 +6,7 @@ require_once '../hostsetting/function.php';
 require_once "../ucenter/active.php";
 require_once "../article/function.php";
 require_once "../redis/function.php";
+require_once "../db/custom_book.php";
 
 add_edit_event(_ARTICLE_EDIT_,$_POST["id"]);
 
@@ -24,97 +25,35 @@ if($power<20){
 
 $_content = $_POST["content"];
 
-/*
-if($_POST["import"]=='on'){
-    $sent = explode("\n",$_POST["content"]);
-    if($sent && count($sent)>0){
-        $setting =  new Hostsetting();
-        $max_book = $setting->get("max_book_number");
-        if($max_book){
-            $currBook = $max_book+1;
-            $setbooknum = $setting->set("max_book_number",$currBook);
-            if($setbooknum==false){
-                $respond["status"]=1;
-                $respond["message"]="设置书号错误";
-                echo json_encode($respond, JSON_UNESCAPED_UNICODE);
-                exit;
-            }
-        }
-        else{
-            $respond["status"]=1;
-            $respond["message"]="获取书号错误";
-            echo json_encode($respond, JSON_UNESCAPED_UNICODE);
-            exit;
-        }
-        PDO_Connect(""._FILE_DB_SENTENCE_);
 
-        # 开始一个事务,关闭自动提交 
-        $PDO->beginTransaction();
-        $query="INSERT INTO sentence ('id','block_id','channal','book','paragraph','begin','end','tag','author','editor','text','language','ver','status','strlen','create_time','modify_time','receive_time') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? , ?, ?)";
-        
-        $sth = $PDO->prepare($query);
-        
-        $para = 1;
-        $sentNum = 0;
-        $newText =  "";
-        foreach ($sent as $data) {
-            $data = trim($data);
-            if($data==""){
-                $para++;
-                $sentNum = 0;
-                $newText .="\n";
-                continue;
-            }
-            else{
-                $sentNum=$sentNum+10;
-            }
-            if(mb_substr($data,0,2,"UTF-8")=="{{"){
-                $newText .=$data."\n";
-            }
-            else{
-                $newText .='{{'."{$currBook}-{$para}-{$sentNum}-{$sentNum}"."}}\n";
-                $sth->execute(
-                        array(UUID::v4(),
-                                    "",
-                                    $_POST["channal"],
-                                    $currBook,
-                                    $para,
-                                    $sentNum,
-                                    $sentNum,
-                                    "",
-                                    "[]",
-                                    $_COOKIE["userid"],
-                                    $data,
-                                    $_POST["lang"],
-                                    1,
-                                    1,
-                                    mb_strlen($data,"UTF-8"),
-                                    mTime(),
-                                    mTime(),
-                                    mTime()
-                                ));                
-            }
+if($_POST["import"]=='on'){
+	#导入自定义书
+	$custom_book = new CustomBook($redis);
+	$_lang = explode("_",$_POST["lang"]);
+	if(count($_lang)===3){
+		$lang = $_lang[2];
+	}
+	else if(count($_lang)===1){
+		$lang = $_lang[0];
+	}
+	else{
+		$respond["status"]=1;
+		$respond["message"]="无法识别的语言".$_POST["lang"];
+		echo json_encode($respond, JSON_UNESCAPED_UNICODE);
+		exit;
+	}
 
-        }
-        $PDO->commit();
-        
-        if (!$sth || ($sth && $sth->errorCode() != 0)) {
-            #  识别错误且回滚更改  
-            $PDO->rollBack();
-            $error = PDO_ErrorInfo();
-            $respond['status']=1;
-            $respond['message']=$error[2];
-            echo json_encode($respond, JSON_UNESCAPED_UNICODE);
-            exit;
-        }
-        else{
-            $respond['status']=0;
-            $respond['message']="成功";
-            $_content = $newText;
-        }		        
-    }
+	$respond = $custom_book->new($_POST["title"],$_content,$lang);
+	if($respond["status"]==0){
+		$_content = $respond["content"];
+	}
+	else{
+		echo json_encode($respond, JSON_UNESCAPED_UNICODE);
+		exit;
+	}
 }
-*/
+
+
 PDO_Connect(_FILE_DB_USER_ARTICLE_);
 
 $query="UPDATE article SET title = ? , subtitle = ? , summary = ?, content = ?  , tag = ? , setting = ? , status = ? , receive_time= ?  , modify_time= ?   where  id = ?  ";

+ 1 - 1
app/article/my_collect_put.php

@@ -26,7 +26,7 @@ PDO_Connect(""._FILE_DB_USER_ARTICLE_);
 $query="INSERT INTO collect ( id,  title  , subtitle  , summary , article_list   , owner, lang  , status  , create_time , modify_time , receive_time   )  VALUES  ( ? , ? , ? , ?  , ? , ? , ? , ? , ? , ? , ? ) ";
 $sth = $PDO->prepare($query);
 $uuid = UUID::v4();
-$sth->execute(array($uuid , $_POST["title"] , "" ,"", "[]" ,  $_COOKIE["userid"] , "" , 1 , mTime() ,  mTime() , mTime() ));
+$sth->execute(array($uuid , $_POST["title"] , "" ,"", "[]" ,  $_COOKIE["userid"] , "" , $_POST["status"] , mTime() ,  mTime() , mTime() ));
 $respond=array("status"=>0,"message"=>"");
 if (!$sth || ($sth && $sth->errorCode() != 0)) {
 	$error = PDO_ErrorInfo();

+ 1 - 1
app/channal/function.php

@@ -47,7 +47,7 @@ class Channal extends Table
 
 	}
 	public function getPower($id){
-		#查询用户对此channel是否有权限		
+		#查询用户对此channel是否有权限
 		if(isset($_COOKIE["userid"])){
 			$userId = $_COOKIE["userid"];
 		}

+ 1 - 2
app/channal/get.php

@@ -27,7 +27,7 @@ foreach ($my_group as $key => $value) {
 $channelList = array();
 
 //找自己的
-PDO_Connect(""._FILE_DB_CHANNAL_);
+PDO_Connect(_FILE_DB_CHANNAL_);
 $query = "SELECT id,owner,name,status,lang FROM channal WHERE owner = ?  LIMIT 0,100";
 $Fetch_my = PDO_FetchAll($query,array($_COOKIE["userid"]));
 
@@ -38,7 +38,6 @@ foreach ($Fetch_my as $key => $value) {
 
 # 找协作的
 $coop_channal =  share_res_list_get($_COOKIE["userid"],2);
-$Fetch_coop = array();
 foreach ($coop_channal as $key => $value) {
 	# return res_id,res_type,power res_title  res_owner_id
 	if(isset($channelList[$value["res_id"]])){

+ 11 - 12
app/channal/my_channal_post.php

@@ -46,7 +46,7 @@ else{
 		}
 	}
     // 设置 句子库和逐词译库可见性
-    PDO_Connect(""._FILE_DB_SENTENCE_);
+    PDO_Connect(_FILE_DB_SENTENCE_);
     $query="UPDATE sentence SET language = ?  , status = ? where  channal = ?  ";
     $sth = PDO_Execute($query,array($_POST["lang"],$_POST["status"],$_POST["id"]));
     if (!$sth || ($sth && $sth->errorCode() != 0)) {
@@ -54,17 +54,16 @@ else{
         $respond['status']=1;
         $respond['message']=$error[2];
     }
-    else{
-        // 设置 逐词译库可见性
-        PDO_Connect(""._FILE_DB_USER_WBW_);
-        $query="UPDATE wbw_block SET lang = ?  , status = ? where  channal = ?  ";
-        $sth = PDO_Execute($query,array($_POST["lang"],$_POST["status"],$_POST["id"]));
-        if (!$sth || ($sth && $sth->errorCode() != 0)) {
-            $error = PDO_ErrorInfo();
-            $respond['status']=1;
-            $respond['message']=$error[2];
-        }
-    }
+
+	// 设置 逐词译库可见性
+	PDO_Connect(_FILE_DB_USER_WBW_);
+	$query="UPDATE wbw_block SET lang = ?  , status = ? where  channal = ?  ";
+	$sth = PDO_Execute($query,array($_POST["lang"],$_POST["status"],$_POST["id"]));
+	if (!$sth || ($sth && $sth->errorCode() != 0)) {
+		$error = PDO_ErrorInfo();
+		$respond['status']=1;
+		$respond['message']=$error[2];
+	}	
 }
 
 echo json_encode($respond, JSON_UNESCAPED_UNICODE);

+ 149 - 0
app/db/custom_book.php

@@ -0,0 +1,149 @@
+<?php
+require_once "../path.php";
+require_once "../db/table.php";
+require_once '../hostsetting/function.php';
+
+class CustomBook extends Table
+{
+    function __construct($redis=false) {
+		parent::__construct(_FILE_DB_USER_CUSTOM_BOOK_, "custom_book", "", "",$redis);
+    }
+
+	public function new($title,$data,$lang)
+	{
+		$respond['status']=0;
+		$respond['message']="";
+		$respond['content']="";
+
+		$sent = explode("\n",$data);
+		if($sent && count($sent)>0){
+			$setting =  new Hostsetting();
+			$max_book = $setting->get("max_book_number");
+			if($max_book){
+				$currBook = $max_book+1;
+				$setbooknum = $setting->set("max_book_number",$currBook);
+				if($setbooknum==false){
+					$respond["status"]=1;
+					$respond["message"]="设置书号错误";
+					return $respond;
+				}
+			}
+			else{
+				$respond["status"]=1;
+				$respond["message"]="获取书号错误";
+				return $respond;
+			}
+
+			$query="INSERT INTO {$this->table} ('book_id','title','owner','lang','status','modify_time','create_time') VALUES (?, ?, ?, ?, ?, ?, ?)";
+
+			$stmt = $this->execute($query,array($currBook,$title,$_COOKIE["userid"],$lang,10,mTime(),mTime()));
+			if($stmt){
+				$CSent = new CustomBookSentence($this->redis);
+				$respond = $CSent->insert($currBook,$sent,$lang);
+			}
+			else{
+				$respond["status"]=1;
+				$respond["message"]="插入新书失败";
+			}
+		}
+		return $respond;
+	}
+}
+
+class CustomBookSentence extends Table
+{
+    function __construct($redis=false) {
+		parent::__construct(_FILE_DB_USER_CUSTOM_BOOK_, "custom_book_sentence", "", "",$redis);
+    }
+
+	public function getAll($book,$para,$start,$end){
+		$query="SELECT text,length,lang,modify_time,create_time,owner FROM custom_book_sentence WHERE book = ? AND paragraph = ? AND begin=? AND end = ?";
+		$result = $this->fetch($query,array($book,$para,$start,$end));
+		if($result){
+			return $result;
+		}
+		else{
+			return array("text"=>"","length"=>"","lang"=>"","modify_time"=>0,"create_time"=>0,"owner"=>"");
+		}
+	}
+
+	public function insert($book,$content,$lang)
+	{
+		$respond['status']=0;
+		$respond['message']="";
+		$respond['content']="";
+		# 开始一个事务,关闭自动提交 
+		$this->dbh->beginTransaction();
+		$query="INSERT INTO custom_book_sentence ('book','paragraph','begin','end','length','text','lang','owner','status','create_time','modify_time') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+		
+		$sth = $this->dbh->prepare($query);
+		
+		$para = 1;
+		$sentNum = 0;
+		$newText =  "";
+		foreach ($content as $data) {
+			$data = trim($data);
+			if($data==""){
+				$para++;
+				$sentNum = 0;
+				$newText .="\n";
+				continue;
+			}
+			else{
+				$sentNum=$sentNum+10;
+			}
+			if(mb_substr($data,0,2,"UTF-8")=="{{"){
+				$newText .=$data."\n";
+			}
+			else{
+				$newText .='{{'."{$book}-{$para}-{$sentNum}-{$sentNum}"."}}\n";
+				$sth->execute(
+						array(
+							$book,
+							$para,
+							$sentNum,
+							$sentNum,
+							mb_strlen($data,"UTF-8"),
+							$data,
+							$lang,
+							$_COOKIE["userid"],
+							10,
+							mTime(),
+							mTime()
+						));                
+			}
+
+		}
+		$this->dbh->commit();
+		
+		if (!$sth || ($sth && $sth->errorCode() != 0)) {
+			#  识别错误且回滚更改  
+			$this->dbh->rollBack();
+			$error = $this->dbh->errorInfo();
+			$respond['status']=1;
+			$respond['message']=$error[2];
+			$respond['content']="";
+		}
+		else{
+			$respond['status']=0;
+			$respond['message']="成功";
+			$respond['content']=$newText;
+		}	
+
+		return $respond;
+	}
+
+	public function getText($book,$para,$start,$end){
+		$query="SELECT text FROM custom_book_sentence WHERE book = ? AND paragraph = ? AND begin=? AND end = ?";
+		$result = $this->fetch($query,array($book,$para,$start,$end));
+		if($result){
+			return $result["text"];
+		}
+		else{
+			return "unkow";
+		}
+	}
+
+}
+
+?>

+ 35 - 0
app/db/table.php

@@ -23,6 +23,41 @@ class Table
 	public function setField($setting){
 		$this->field_setting = $setting;
 	}
+	protected function fetch($query,$params){
+		if (isset($params)) {
+			$stmt = $this->dbh->prepare($query);
+			if($stmt){
+				$stmt->execute($params);
+			}
+			
+		} else {
+			$stmt = $PDO->query($query);
+		}
+		if($stmt){
+			return $stmt->fetch(PDO::FETCH_ASSOC);
+		}
+		else{
+			return false;
+		}
+	}
+
+	function execute($query, $params=null){
+		if (isset($params)) {
+			$stmt = $this->dbh->prepare($query);
+			if($stmt){
+				$stmt->execute($params);
+				return $stmt;				
+			}
+			else{
+				return false;
+			}
+
+		} else {
+			return $this->dbh->query($query);
+		}
+	}
+
+
 	public function syncList($time){
 
 	}

+ 29 - 0
app/db/wbw_block.php

@@ -0,0 +1,29 @@
+<?php
+require_once "../path.php";
+require_once "../db/table.php";
+require_once "../channal/function.php";
+
+class WbwBlock extends Table
+{
+    function __construct($redis=false) {
+		parent::__construct(_FILE_DB_USER_WBW_, "wbw_block", "", "",$redis);
+    }
+
+	public function getPower($blockId){
+		$channelInfo = new Channal($this->redis);
+		$power = 0;
+		$query = "SELECT channal,owner from wbw_block   where id= ?  ";
+		$row = $this->fetch($query,array($blockId));
+		if($row ){
+			if(empty($row["channal"])){
+				if($row["owner"]==$_COOKIE["userid"]){
+					$power = 30;
+				}
+			}
+			else{
+				$power = $channelInfo->getPower($row["channal"]);
+			}
+		}
+		return $power;
+	}
+}

+ 281 - 0
app/doc/fork_channel.php

@@ -0,0 +1,281 @@
+<?php
+
+/*拷贝其他人的文件
+ *
+ *
+ */
+require_once '../studio/index_head.php';
+?>
+<body id="file_list_body" >
+<?php
+require_once "../path.php";
+require_once "../public/_pdo.php";
+require_once "../public/function.php";
+require_once "../channal/function.php";
+require_once "../redis/function.php";
+
+$redis = redis_connect();
+
+require_once '../studio/index_tool_bar.php';
+
+echo '<div class="index_inner" style="    margin-left: 18em;margin-top: 5em;">';
+
+if ($_COOKIE["uid"]) {
+    $uid = $_COOKIE["uid"];
+} else {
+    echo "尚未登录";
+    echo "<h3><a href='../ucenter/index.php?op=login'>登录</a>后才可以打开文档 </h3>";
+    exit;
+}
+
+if(isset($_GET["para"])){
+    $_para = json_decode($_GET["para"]);
+}
+else{
+    echo "没有 para 编号";
+    exit;
+}
+
+if (isset($_GET["src_channel"]) == false) {
+    echo "没有 channel 编号";
+    exit;
+}
+    //文档信息
+    $mbook = $_GET["book"];
+    $paragraph = implode(",",$_para);
+
+if (isset($_GET["dest_channel"]) == false) {
+    echo '<div class="file_list_block">';
+    echo "<h2>选择一个空白的版风存储新的文档</h2>";
+    echo "<div>原有版本中相同段落的数据将被覆盖</div>";
+    echo "<form action='fork_channel.php' method='get'>";
+    echo "<input type='hidden' name='book' value='{$_GET["book"]}' />";
+    echo "<input type='hidden' name='para' value='{$_GET["para"]}' />";
+    echo "<input type='hidden' name='src_channel' value='{$_GET["src_channel"]}' />";
+    PDO_Connect(_FILE_DB_CHANNAL_);
+    $query = "select * from channal where owner = '{$_COOKIE["userid"]}'   limit 0,100";
+    $Fetch = PDO_FetchAll($query);
+    $i = 0;
+    PDO_Connect( _FILE_DB_USER_WBW_);	
+    foreach ($Fetch as $row) {
+        echo '<div class="file_list_row" style="padding:5px;display:flex;">';
+
+        echo '<div class="pd-10"  style="max-width:2em;flex:1;">';
+        echo '<input name="dest_channel" value="' . $row["id"] . '" ';
+        if ($i == 0) {
+            echo "checked";
+        }
+        echo ' type="radio" />';
+        echo '</div>';
+        echo '<div class="title" style="flex:3;padding-bottom:5px;">' . $row["name"] . '</div>';
+        echo '<div class="title" style="flex:3;padding-bottom:5px;">' . $row["lang"] . '</div>';
+        echo '<div class="title" style="flex:2;padding-bottom:5px;">';
+        $query = "select count(*) from wbw_block where channal = '{$row["id"]}' and book='{$mbook}' and paragraph in ({$paragraph})  limit 0,100";
+        $FetchWBW = PDO_FetchOne($query);
+        echo '</div>';
+        echo '<div class="title" style="flex:2;padding-bottom:5px;">';
+        if ($FetchWBW == 0) {
+            echo $_local->gui->blank;
+        } else {
+            echo $FetchWBW . $_local->gui->para;
+            echo "<a href='../studio/editor.php?op=openchannal&book=$book&para={$paraList}&channal={$row["id"]}'>open</a>";
+        }
+        echo '</div>';
+
+        echo '<div class="summary"  style="flex:1;padding-bottom:5px;">' . $row["status"] . '</div>';
+        echo '<div class="author"  style="flex:1;padding-bottom:5px;">' . $row["create_time"] . '</div>';
+
+        echo '</div>';
+        $i++;
+    }
+    echo "<input type='submit' />";
+    echo "</form>";
+    echo "</div>";
+    exit;
+}
+
+PDO_Connect( _FILE_DB_USER_WBW_);	
+
+$channelInfo= new Channal($redis);
+
+$srcPower = (int)$channelInfo->getPower($_GET["src_channel"]);
+
+{
+
+	{
+
+        if ($srcPower == 30) {
+            //自己的文档
+            echo "这是自己的文档,不能复刻。";
+        } else {
+            //别人的文档
+            //查询以前自己是否曾经复刻
+            $query = "select * from wbw_block where parent_channel=? and owner=? ";
+            $FetchSelf = PDO_FetchAll($query,array($_GET["src_channel"],$_COOKIE["userid"]));
+            $iFetchSelf = count($FetchSelf);
+            if ($iFetchSelf > 0) {
+                //以前打开过
+                echo "文档已经复刻";
+                echo "正在<a href='../studio/editor.php?op=openchannal&book={$_GET["book"]}&para={$_para[0]}&channal={$FetchSelf[0]["channal"]}'>打开</a>文档";
+                echo "<script>";
+                echo "window.location.assign(\"../studio/editor.php?op=openchannal&book={$_GET["book"]}&para={$_para[0]}&channal={$FetchSelf[0]["channal"]}\");";
+                echo "</script>";
+            } else {
+                //以前没打开过
+                echo "<h3>共享的文档,正在fork...</h3>";
+                echo "<div style='display:none;'>";
+
+				{
+                    //复制数据
+                    //打开逐词解析数据库
+                    $dns = _FILE_DB_USER_WBW_;
+                    $dbhWBW = new PDO($dns, "", "", array(PDO::ATTR_PERSISTENT => true));
+                    $dbhWBW->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+
+                    //逐词解析新数据数组
+                    $arrNewBlock = array();
+                    $arrNewBlockData = array();
+                    $arrBlockTransform = array();
+
+                    $blocks = $_para;
+                    for ($i = 0; $i < count($blocks); $i++) {
+						$query = "select id from wbw_block where book= ? and paragraph = ? and channal = ? ";
+						$stmt = $dbhWBW->prepare($query);
+						$stmt->execute(array($_GET["book"],$iPara,$_GET["dest_channel"]));
+						$fDest = $stmt->fetch(PDO::FETCH_ASSOC);
+						if($fDest){
+							#旧的逐词解析数据块wbw_block id 
+							$destId = $fDest["id"];
+						}
+						#逐词解析
+						$iPara = $blocks[$i];
+						$query = "select * from wbw_block where book= ? and paragraph = ? and channal = ? ";
+						$stmt = $dbhWBW->prepare($query);
+						$stmt->execute(array($_GET["book"],$iPara,$_GET["src_channel"]));
+						$fBlock = $stmt->fetchAll(PDO::FETCH_ASSOC);
+						if(isset($destId)){
+							$newBlockId = $destId;
+						}
+						else{
+							$newBlockId = UUID::V4();
+						}
+						$arrBlockTransform[$fBlock[0]["id"]] = $newBlockId;
+						if (count($fBlock) > 0) {
+							array_push($arrNewBlock,
+								array($newBlockId,
+									"",
+									$_GET["dest_channel"],
+									$_GET["src_channel"],
+									$_COOKIE["userid"],
+									$fBlock[0]["book"],
+									$fBlock[0]["paragraph"],
+									$fBlock[0]["style"],
+									$fBlock[0]["lang"],
+									$fBlock[0]["status"],
+									mTime(),
+									mTime(),
+									mTime()
+								));
+						}
+
+						$query = "select * from wbw where block_id= ? ";
+						$stmtWBW = $dbhWBW->prepare($query);
+						$stmtWBW->execute(array($fBlock[0]["id"]));
+						$fBlockData = $stmtWBW->fetchAll(PDO::FETCH_ASSOC);
+						foreach ($fBlockData as $value) {
+							array_push($arrNewBlockData,
+								array(UUID::V4(),
+									$arrBlockTransform[$value["block_id"]],
+									$value["book"],
+									$value["paragraph"],
+									$value["wid"],
+									$value["word"],
+									$value["data"],
+									mTime(),
+									mTime(),
+									$value["status"],
+									$_COOKIE["userid"],
+								));
+
+						}
+
+                    }
+
+					# 查找目标block是否存在
+
+					//删除旧的逐词解析block数据块
+					$query = "DELETE from wbw_block where  paragraph = ? AND book = ? AND channal = ? ";
+					$stmt = $dbhWBW->prepare($query);
+					$stmt->execute(array($iPara,$_GET["book"],$_GET["dest_channel"]));
+					
+                    //新增逐词解析block数据块
+                    if (count($arrNewBlock) > 0) {
+                        $dbhWBW->beginTransaction();
+                        $query = "INSERT INTO wbw_block ('id','parent_id','channal','parent_channel','owner','book','paragraph','style','lang','status','modify_time','receive_time','create_time') VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)";
+                        $stmtNewBlock = $dbhWBW->prepare($query);
+                        foreach ($arrNewBlock as $oneParam) {
+                            $stmtNewBlock->execute($oneParam);
+                        }
+                        // 提交更改
+                        $dbhWBW->commit();
+                        if (!$stmtNewBlock || ($stmtNewBlock && $stmtNewBlock->errorCode() != 0)) {
+                            $error = $dbhWBW->errorInfo();
+                            echo "error - $error[2] <br>";
+							exit;
+                        } else {
+                            //逐词解析block块复刻成功
+                            $count = count($arrNewBlock);
+                            echo "wbw block $count recorders.<br/>";
+                        }
+                    }
+
+					//删除逐词解析数据块
+					if(isset($destId)){
+						$query = "DELETE from wbw where  block_id = ? ";
+						$stmt = $dbhWBW->prepare($query);
+						$stmt->execute($destId);
+					}
+					
+                    if (count($arrNewBlockData) > 0) {
+                        // 开始一个事务,逐词解析数据 关闭自动提交
+                        $dbhWBW->beginTransaction();
+                        $query = "INSERT INTO wbw ('id','block_id','book','paragraph','wid','word','data','modify_time','receive_time','status','owner') VALUES (?,?,?,?,?,?,?,?,?,?,?)";
+                        $stmtWbwData = $dbhWBW->prepare($query);
+                        foreach ($arrNewBlockData as $oneParam) {
+                            $stmtWbwData->execute($oneParam);
+                        }
+                        // 提交更改
+                        $dbhWBW->commit();
+                        if (!$stmtWbwData || ($stmtWbwData && $stmtWbwData->errorCode() != 0)) {
+                            $error = $dbhWBW->errorInfo();
+                            echo "error - $error[2] <br>";
+							exit;
+                        } else {
+                            //逐词解析 数据 复刻成功
+                            $count = count($arrNewBlockData);
+                            echo "new wbw $count recorders.";
+                        }
+                    }
+
+                   {
+                        //成功
+                        echo "doc list updata 1 recorders.";
+                        echo "</div>";
+                        echo "<h3>复刻成功</h3>";
+                        echo "正在<a href='../studio/editor.php?op=openchannal&book={$_GET["book"]}&para={$_para[0]}&channal={$_GET["dest_channel"]}'>打开</a>文档";
+                        echo "<script>";
+                        echo "window.location.assign(\"../studio/editor.php?op=openchannal&book={$_GET["book"]}&para={$_para[0]}&channal={$_GET["dest_channel"]}\");";
+                        echo "</script>";
+                    }
+                }
+
+            }
+        }
+    }
+}
+
+echo "</div>";
+?>
+
+</body>
+</html>

+ 1 - 0
app/path.php

@@ -121,3 +121,4 @@ define("_FILE_DB_USER_SENTENCE_HISTORAY_", "sqlite:" . __DIR__ . "/../tmp/user/u
 define("_FILE_DB_USER_ACTIVE_", "sqlite:" . __DIR__ . "/../tmp/user/user_active.db3");
 define("_FILE_DB_USER_ACTIVE_LOG_", "sqlite:" . __DIR__ . "/../tmp/user/user_active_log.db3");
 define("_FILE_DB_USER_SHARE_", "sqlite:" . __DIR__ . "/../tmp/user/share.db3");
+define("_FILE_DB_USER_CUSTOM_BOOK_", "sqlite:" . __DIR__ . "/../tmp/user/custom_book.db3");

+ 1 - 1
app/pcdl/html_head.php

@@ -62,7 +62,7 @@ if (isset($_GET["language"])) {
 
 	<title id="page_title">wikipāḷi</title>
 
-	<script src="../public/js/jquery.js"></script>
+	<script src="../../node_modules/jquery/dist/jquery.js"></script>
 	<script src="../public/js/comm.js"></script>
 	<script src="../studio/js/fixedsticky.js"></script>
 	<script src="../guide/guide.js"></script>

+ 1 - 1
app/studio/dict_find_one.php

@@ -83,7 +83,7 @@ if ($dict_name == "") {
 } else {
     $dict_list = str_getcsv($dict_name, ',');
     foreach ($dict_list as $dict) {
-        $db_file_list[] = array( $dict,"");
+        $db_file_list[] = array( $dict,"",false);
     }
 }
 

+ 1 - 0
app/studio/js/render.js

@@ -2256,6 +2256,7 @@ function renderWordDetailByElement_edit_a(xmlElement) {
 			currMeaning = getLocalFormulaStr(currGramma, cutString(currMeaning, sReal.length * 6));
 		}
 
+		currMeaning = currMeaning.replace(/ /g, "&nbsp;");
 		renderMeaning = currMeaning.replace(/{/g, "<span class='grm_add_mean'>");
 		renderMeaning = renderMeaning.replace(/}/g, "</span>");
 		renderMeaning = renderMeaning.replace(/\[/g, "<span class='grm_add_mean_user'>");

File diff suppressed because it is too large
+ 3 - 52
app/studio/svg/icon.svg


+ 25 - 10
app/term/channal_list.php

@@ -6,6 +6,12 @@ require_once "../path.php";
 require_once '../channal/function.php';
 require_once '../ucenter/function.php';
 require_once '../share/function.php';
+require_once '../db/custom_book.php';
+require_once '../redis/function.php';
+
+$redis = redis_connect();
+
+$custom_book = new CustomBookSentence($redis);
 
 $log = "";
 $timeStart = microtime(true);
@@ -95,16 +101,25 @@ foreach ($_data as $key => $value) {
     try {
         # 查询句子长度
         $pali_letter["id"] = $arrInfo[0];
-        $query = "SELECT length FROM pali_sent WHERE book= ? AND paragraph= ? AND begin= ? AND end= ?  ";
-        $stmt = $db_pali_sent->prepare($query);
-        $stmt->execute(array($bookId, $para, $begin, $end));
-        $Fetch = $stmt->fetch(PDO::FETCH_ASSOC);
-        if ($Fetch) {
-            $pali_letter["len"] = $Fetch["length"];
-            $article_len += $Fetch["length"];
-        } else {
-            $pali_letter["len"] = 0;
-        }
+
+		if($bookId<1000){
+			$query = "SELECT length FROM pali_sent WHERE book= ? AND paragraph= ? AND begin= ? AND end= ?  ";
+			$stmt = $db_pali_sent->prepare($query);
+			$stmt->execute(array($bookId, $para, $begin, $end));
+			$Fetch = $stmt->fetch(PDO::FETCH_ASSOC);
+			if ($Fetch) {
+				$pali_letter["len"] = $Fetch["length"];
+				$article_len += $Fetch["length"];
+			} else {
+				$pali_letter["len"] = 0;
+			}			
+		}
+		else{
+			$sentInfo = $custom_book->getAll($bookId, $para, $begin, $end);
+			$pali_letter["len"] = $sentInfo["length"];
+			$article_len += $sentInfo["length"];
+		}
+
 
         #公开 或 channel有权限的
         $query = "SELECT channal FROM sentence WHERE book= ? AND paragraph= ? AND begin= ? AND end= ?  AND strlen >0 and (status = 30 {$channel_query} ) group by channal  limit 0 ,20 ";

+ 35 - 53
app/term/note.js

@@ -363,6 +363,9 @@ function find_channal(id) {
 	}
 	return false;
 }
+
+//生成版本列表
+//选择列表中的版本切换页面
 function render_channal_list(channalinfo) {
 	let output = "";
 	let checked = "";
@@ -971,9 +974,9 @@ function render_one_sent_tran_a(iterator, diff = false) {
 		html += iterator.channalinfo.name;
 	}
 	html += "</span>";
-	html += '<span class="name editor_name" '
+	html += '<span class="name editor_name" ';
 	if (typeof iterator.channalinfo == "undefined") {
-		html += '>';
+		html += ">";
 		html += "unkown";
 	} else {
 		html += 'title="' + iterator.channalinfo.name + gLocal.gui.recent_update + '">';
@@ -1599,47 +1602,25 @@ function note_sent_save_a(obj) {
 	let channal = $(obj).attr("channel");
 	let text = $(obj).val();
 	let sent_tran_div = find_sent_tran_div(obj);
-	/*
-	var jqxhr = $.post("example.php", function() {
-	  alert("success");
+
+	$.ajaxSetup({
+		timeout: 5000,
+	});
+
+	$.post("../usent/sent_post.php", {
+		id: id,
+		book: book,
+		para: para,
+		begin: begin,
+		end: end,
+		channal: channal,
+		text: text,
+		lang: "zh",
 	})
-	.success(function() { alert("second success"); })
-	.error(function() { alert("error"); })
-	.complete(function() { alert("complete"); });*/
-	/*
-	function (data, status) {
-			alert("异常!" + data.responseText);
-			switch (status) {
-				case "timeout":
-					break;
-				case "error":
-					break;
-				case "notmodified":
-					break;
-				case "parsererror":
-					break;
-				default:
-					break;
-			}
-	*/
-	var jqxhr = $.post(
-		"../usent/sent_post.php",
-		{
-			id: id,
-			book: book,
-			para: para,
-			begin: begin,
-			end: end,
-			channal: channal,
-			text: text,
-			lang: "zh",
-		},
-		sent_save_callback
-	)
-		.success(function () {
-			//alert("second success");
+		.done(function (data) {
+			sent_save_callback(data);
 		})
-		.error(function (xhr, error, data) {
+		.fail(function (xhr, error, data) {
 			let sid = book + "-" + para + "-" + begin + "-" + end;
 
 			let sent_tran_div = $(".sent_tran[channel='" + channal + "'][sid='" + sid + "']");
@@ -1660,26 +1641,22 @@ function note_sent_save_a(obj) {
 				default:
 					break;
 			}
-		})
-		.complete(function (xhr, data) {
-			//请求完成后回调函数 (请求成功或失败之后均调用)。
-			switch (data) {
-				case "error":
-					break;
-				case "success":
-					break;
-				default:
-					break;
-			}
 		});
 
 	if (sent_tran_div) {
 		$(sent_tran_div).addClass("loading");
+		$(sent_tran_div).removeClass("error");
 	}
 }
 function update_sent_tran(sentData) {}
 function sent_save_callback(data) {
-	let result = JSON.parse(data);
+	let result;
+	try {
+		result = JSON.parse(data);
+	} catch (e) {
+		alert(e.message);
+		return;
+	}
 	if (result.status > 0) {
 		alert("error" + result.message);
 	} else {
@@ -2037,3 +2014,8 @@ function setDisplay(obj) {
 		_display = "sent";
 	}
 }
+
+//获取文章中H 并渲染为目录
+function render_heading_toc() {
+	//$(":header")
+}

+ 13 - 4
app/term/note.php

@@ -7,6 +7,7 @@ require_once "../ucenter/function.php";
 require_once "../usent/function.php";
 require_once "../pali_text/function.php";
 require_once "../redis/function.php";
+require_once "../db/custom_book.php";
 
 $redis = redis_connect();
 
@@ -88,6 +89,7 @@ if (count($channal_list) > 0) {
 }
 
 # 查询有阅读权限的channel 结束
+$custom_book = new CustomBookSentence($redis);
 
 foreach ($_data as $key => $value) {
     # code...
@@ -112,10 +114,17 @@ foreach ($_data as $key => $value) {
     }
 	$pali_sim = 0;
     if ($redis != false) {
-        $result = $redis->hGet('pali://sent/' . $bookId . "_" . $para . "_" . $begin . "_" . $end,"pali");
-		$palitext = $result;
-		$pali_text_id = $redis->hGet('pali://sent/' . $bookId . "_" . $para . "_" . $begin . "_" . $end,"id");
-		$pali_sim = $redis->hGet('pali://sent/' . $bookId . "_" . $para . "_" . $begin . "_" . $end,"sim_count");
+		if($bookId<1000){
+			$result = $redis->hGet('pali://sent/' . $bookId . "_" . $para . "_" . $begin . "_" . $end,"pali");
+			$palitext = $result;
+			$pali_text_id = $redis->hGet('pali://sent/' . $bookId . "_" . $para . "_" . $begin . "_" . $end,"id");
+			$pali_sim = $redis->hGet('pali://sent/' . $bookId . "_" . $para . "_" . $begin . "_" . $end,"sim_count");
+		}
+		else{
+			$palitext = $custom_book->getText($bookId,$para,$begin,$end);
+			$pali_text_id = 0;
+		}
+
     } else {
         $query = "SELECT id,html FROM 'pali_sent' WHERE book = ? AND paragraph = ? AND begin = ? AND end = ? ";
         $sth = $db_pali_sent->prepare($query);

+ 25 - 4
app/term/term.css

@@ -194,6 +194,12 @@ blockquote {
 	padding-left: 5px;
 }
 
+.read blockquote {
+	font-size: 80%;
+	color: var(--main-color1);
+	background-color: #7d7d7d1f;
+}
+
 note > .tran {
 	color: #5c5c5c;
 	padding-left: 1em;
@@ -294,12 +300,21 @@ note > .tran .tran_text_tool_bar::after,
 
 note > .palitext,
 .palitext {
-	font-family: Noto serif;
 	line-height: 1.5em;
 	color: #9f3a01;
-	font-weight: 500;
 	margin: 4px;
 }
+h1 .palitext {
+	font-family: "Noto Serif", "Noto Sans TC", "Noto Sans SC";
+	font-weight: 700;
+	font-size: 130%;
+}
+h2 .palitext {
+	font-family: "Noto Serif", "Noto Sans TC", "Noto Sans SC";
+	font-weight: 700;
+	font-size: 120%;
+}
+
 note n {
 	display: inline;
 	color: blue;
@@ -827,6 +842,8 @@ w:hover {
 }
 .horizontal .sent_tran_div {
 	flex: 5;
+	display: flex;
+	flex-direction: column;
 }
 
 /*段落模式*/
@@ -880,9 +897,13 @@ span.keybutton {
 	word-break: break-word;
 }
 span.tran_sent {
-	display: block;
+	line-height: 1.7em;
+}
+.tran_sent ul,
+.tran_sent li {
+	list-style-type: unset;
+	margin-left: 1em;
 }
-
 .icon_sent_status {
 	display: none;
 	width: 22px;

+ 0 - 39
app/uwbw/sync_block.php

@@ -1,39 +0,0 @@
-<?php
-//header('Content-type: application/json; charset=utf8');
-
-require_once "../path.php";
-require_once "../sync/function.php";
-
-$input = (object) [
-    "database" =>  _FILE_DB_USER_WBW_,
-    "table" =>  "wbw_block",
-    "uuid" =>  "id",
-    "modify_time" =>  "modify_time",
-    "receive_time" =>  "receive_time",
-    "insert" => [
-        "id",
-        "parent_id",
-        "book",
-        "paragraph",
-        "owner",
-        "lang",
-        "author",
-        "editor",
-        "tag",
-        "status",
-        "modify_time",
-        "receive_time"
-    ],
-    "update" =>  [
-        "lang",
-        "author",
-        "editor",
-        "tag",
-        "status",
-        "receive_time"
-    ]    
-];
-
-do_sync($input);
-
-?>

+ 0 - 39
app/uwbw/sync_wbw.php

@@ -1,39 +0,0 @@
-<?php
-//header('Content-type: application/json; charset=utf8');
-
-require_once "../path.php";
-require_once "../sync/function.php";
-
-$input = (object) [
-    "database" =>  _FILE_DB_USER_WBW_,
-    "table" =>  "wbw",
-    "uuid" =>  "id",
-    "modify_time" =>  "modify_time",
-    "receive_time" =>  "receive_time",
-    "insert" => [
-        "id",
-        "parent_id",
-        "book",
-        "paragraph",
-        "owner",
-        "lang",
-        "author",
-        "editor",
-        "tag",
-        "status",
-        "modify_time",
-        "receive_time"
-    ],
-    "update" =>  [
-        "lang",
-        "author",
-        "editor",
-        "tag",
-        "status",
-        "receive_time"
-    ]    
-];
-
-do_sync($input);
-
-?>

+ 29 - 2
app/uwbw/update.php

@@ -7,9 +7,15 @@ require_once "../public/_pdo.php";
 require_once "../public/function.php";
 require_once "../ucenter/active.php";
 require_once "../redis/function.php";
+require_once "../channal/function.php";
+require_once "../db/wbw_block.php";
+
 
 $respond['status'] = 0;
 $respond['message'] = "";
+$redis = redis_connect();
+$channelInfo = new Channal($redis);
+$_WbwBlock = new WbwBlock($redis);
 
 if (isset($_POST["data"])) {
     $aData = json_decode($_POST["data"]);
@@ -25,13 +31,29 @@ if (count($aData) > 0) {
 
     PDO_Connect(_FILE_DB_USER_WBW_);
 
+	#确定block id 的写入权限
+	$listBlockId=array();
+	foreach ($aData as $data) {
+        $listBlockId[$data->block_id]=0;
+    }
+	#查询channel 的 权限
+	$maxPower=0;
+	foreach ($listBlockId as $key => $value) {
+		$listBlockId[$key] = $_WbwBlock->getPower($key);
+		if($listBlockId[$key]>$maxPower){
+			$maxPower = $listBlockId[$key];
+		}
+	}
+
     /* 开始一个事务,关闭自动提交 */
     $PDO->beginTransaction();
     $query = "UPDATE wbw SET data= ?  , receive_time= ?  , modify_time= ?   where block_id= ?  and wid= ?  ";
     $sth = $PDO->prepare($query);
 
     foreach ($aData as $data) {
-        $sth->execute(array($data->data, mTime(), $data->time, $data->block_id, $data->word_id));
+		if($listBlockId[$data->block_id]>=20){
+			$sth->execute(array($data->data, mTime(), $data->time, $data->block_id, $data->word_id));
+		}
     }
     $PDO->commit();
 
@@ -48,9 +70,14 @@ if (count($aData) > 0) {
         $respond['status'] = 0;
         $respond['message'] = "成功";
     }
+	
+	if($maxPower<20){
+		$respond['status'] = 1;
+        $respond['message'] = "没有修改权限";
+	}
 	if (count($aData) ==1){
-		$redis = redis_connect();
 		try {
+			#将数据插入redis 作为自动匹配最新数据
 			if($redis){
 				$xmlString = "<root>" . $data->data . "</root>";
 				$xmlWord = simplexml_load_string($xmlString);

+ 45 - 7
app/uwbw/wbw_channal_list.js

@@ -33,19 +33,45 @@ function wbw_channal_list_open(book, paralist) {
 				let html = "";
 				for (let index = 0; index < _wbw_channel.data.length; index++) {
 					const element = _wbw_channel.data[index];
-					html += "<div style='display:flex;line-height: 2.5em;'>";
-					html += "<span style='flex:2'>";
-					html += "<button onclick=\"wbw_create('" + index + "')\">";
+					html += "<div style='display:flex;line-height: 2.5em;border-bottom: 1px solid gray;'>";
+					html += "<span style='flex:4'>";
+					let style = "";
+					let text = "";
 					if (parseInt(element.wbw_para) > 0) {
-						html += gLocal.gui.open;
+						if (parseInt(element.power) < 20) {
+							text = "查看";
+							style = "background-color: yellow;";
+						} else {
+							text = gLocal.gui.edit;
+							style = "background-color: greenyellow;";
+						}
 					} else {
-						html += gLocal.gui.new;
+						text = gLocal.gui.new;
+					}
+					html +=
+						"<button style='" + style + "' onclick=\"wbw_create('" + index + "')\">" + text + "</button>";
+
+					if (parseInt(element.power) < 30) {
+						html += "<button onclick=\"wbw_fork('" + index + "')\">";
+						html += "复制到";
+						html += "</button>";
 					}
 
-					html += "</button>";
 					html += "</span>";
 					html += "<span  style='flex:1'>" + (index + 1) + "</span>";
-					html += "<span style='flex:3'>" + element.name + "</span>";
+					html += "<span style='flex:5'>" + element.name + "</span>";
+					html += "<span style='flex:1'>";
+					let power = [
+						{ id: 10, note: "查看者" },
+						{ id: 20, note: "编辑者" },
+						{ id: 30, note: "拥有者" },
+					];
+					for (const iterator of power) {
+						if (parseInt(element.power) == iterator.id) {
+							html += iterator.note;
+						}
+					}
+					html += "</span>";
 					html += "<span style='flex:2'>" + element.lang + "</span>";
 					html += "<span style='flex:2;display:none;'>" + element.wbw_para + "/" + element.count + "</span>";
 					html += "</div>";
@@ -87,3 +113,15 @@ function wbw_create(index) {
 		}
 	);
 }
+
+function wbw_fork(index) {
+	$("#wbw_channal_list_dlg").dialog("close");
+	let url =
+		"../doc/fork_channel.php?book=" +
+		_wbw_channel.book +
+		"&para=" +
+		_wbw_channel.para +
+		"&src_channel=" +
+		_wbw_channel.data[index].id;
+	window.open(url, "_blank");
+}

+ 58 - 8
app/uwbw/wbw_channel_list.php

@@ -2,6 +2,11 @@
 require_once '../path.php';
 require_once "../public/_pdo.php";
 require_once "../public/function.php";
+require_once '../share/function.php';
+require_once '../channal/function.php';
+require_once '../redis/function.php';
+
+$redis = redis_connect();
 
 $output["status"] = 0;
 $output["error"] = "";
@@ -23,19 +28,64 @@ $place_holders = implode(',', array_fill(0, count($_para), '?'));
 $params = $_para;
 $params[] = $_book;
 
-PDO_Connect("" . _FILE_DB_CHANNAL_);
-$query = "SELECT * FROM channal WHERE owner = ?  LIMIT 0,100";
+#查重复
+$channelList = array();
+
+PDO_Connect(_FILE_DB_CHANNAL_);
+$query = "SELECT id FROM channal WHERE owner = ?  LIMIT 0,100";
 $FetchChannal = PDO_FetchAll($query, array($_COOKIE["userid"]));
+
+foreach ($FetchChannal as $key => $value) {
+	# code...
+	$channelList[$value["id"]]=array("power"=>30);
+}
+
+# 找协作的
+$coop_channal =  share_res_list_get($_COOKIE["userid"],2);
+foreach ($coop_channal as $key => $value) {
+	# return res_id,res_type,power res_title  res_owner_id
+	if(isset($channelList[$value["res_id"]])){
+		if($channelList[$value["res_id"]]<(int)$value["power"]){
+			$channelList[$value["res_id"]]=array("power"=>(int)$value["power"]);
+		}
+	}
+	else{
+		$channelList[$value["res_id"]]=array("power"=>(int)$value["power"]);
+	}
+}
+
+# 查询全网公开 的
+PDO_Connect( _FILE_DB_USER_WBW_);
+$query = "SELECT  channal FROM wbw_block WHERE  paragraph IN ($place_holders)  AND book = ? AND channal IS NOT NULL AND status = 30 group by channal ";
+$publicChannel = PDO_FetchAll($query, $params);
+foreach ($publicChannel as $key => $channel) {
+	# code...
+	if(!isset($channelList[$channel["channal"]])){
+		$channelList[$channel["channal"]]=array("power"=>10);
+	}
+}
+
+$channelInfo = new Channal($redis);
 $i = 0;
-foreach ($FetchChannal as $key => $row) {
-    PDO_Connect("" . _FILE_DB_USER_WBW_);
+$outputData = array();
 
+
+foreach ($channelList as $key => $row) {
     $queryParam = $params;
-    $queryParam[] = $row["id"];
+    $queryParam[] = $key;
     $query = "SELECT count(*) FROM wbw_block WHERE  paragraph IN ($place_holders)  AND book = ? AND channal = ? ";
     $wbwCount = PDO_FetchOne($query, $queryParam);
-    $FetchChannal[$key]["wbw_para"] = $wbwCount;
-    $FetchChannal[$key]["count"] = count($_para);
+    $channelList[$key]["wbw_para"] = $wbwCount;
+    $channelList[$key]["count"] = count($_para);
+	$info = $channelInfo->getChannal($key);
+    $channelList[$key]["id"] = $info["id"];
+    $channelList[$key]["name"] = $info["name"];
+    $channelList[$key]["lang"] = $info["lang"];
+	$outputData[]=$channelList[$key];
 }
-$output["data"] = $FetchChannal;
+
+
+
+
+$output["data"] = $outputData;
 echo json_encode($output, JSON_UNESCAPED_UNICODE);

+ 13 - 2
dashboard/.editorconfig

@@ -1,9 +1,20 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
 # dependencies
-/node_modules/
+/node_modules
+/npm-debug.log*
+/yarn-error.log
 /yarn.lock
+/package-lock.json
 
 # production
-/dist/
+/dist
+
+# misc
+.DS_Store
 
 # umi
 /src/.umi
+/src/.umi-production
+/src/.umi-test
+/.env.local

+ 1 - 0
dashboard/.umirc.ts

@@ -7,4 +7,5 @@ export default defineConfig({
   routes: [
     { path: '/', component: '@/pages/index' },
   ],
+  fastRefresh: {},
 });

+ 40 - 0
dashboard/README.md

@@ -0,0 +1,40 @@
+# Usage
+
+```bash
+# install dependencies
+yarn install
+# start the dev server
+yarn start
+```
+
+## Getting Started in **7** days
+
+### Day 1: Prepare
+
+- [TypeScript for JavaScript Programmers](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)
+- [Install ubuntu@wls(ONLY For Windows User)](https://ubuntu.com/wsl)
+- [Start continer](../docker)
+- How to use tmux
+  
+  ```text
+  Ctrl+b %
+  Ctrl+b "
+  Ctrl+b up
+  Ctrl+b down
+  Ctrl+b left
+  Ctrl+b right
+  ```
+
+- Start backend & frontend server
+
+### Day 2
+
+### Day 3
+
+### Day 4
+
+### Day 5
+
+### Day 6
+
+### Day 7

+ 11 - 5
dashboard/package.json

@@ -20,13 +20,19 @@
     ]
   },
   "dependencies": {
+    "@ant-design/pro-layout": "^6.5.0",
     "@umijs/preset-react": "1.x",
-    "@umijs/test": "^3.2.3",
+    "umi": "^3.4.25"
+  },
+  "devDependencies": {
+    "@types/react": "^17.0.0",
+    "@types/react-dom": "^17.0.0",
+    "@umijs/test": "^3.4.25",
     "lint-staged": "^10.0.7",
-    "prettier": "^1.19.1",
-    "react": "^16.12.0",
-    "react-dom": "^16.12.0",
-    "umi": "^3.2.3",
+    "prettier": "^2.2.0",
+    "react": "17.x",
+    "react-dom": "17.x",
+    "typescript": "^4.1.2",
     "yorkie": "^2.0.0"
   }
 }

+ 0 - 4
dashboard/src/pages/index.less

@@ -1,7 +1,3 @@
-
-.normal {
-}
-
 .title {
   background: rgb(121, 242, 157);
 }

+ 1 - 2
dashboard/src/pages/index.tsx

@@ -1,7 +1,6 @@
-import React from 'react';
 import styles from './index.less';
 
-export default () => {
+export default function IndexPage() {
   return (
     <div>
       <h1 className={styles.title}>Page index</h1>

+ 12 - 1
dashboard/tsconfig.json

@@ -4,7 +4,7 @@
     "module": "esnext",
     "moduleResolution": "node",
     "importHelpers": true,
-    "jsx": "react",
+    "jsx": "react-jsx",
     "esModuleInterop": true,
     "sourceMap": true,
     "baseUrl": "./",
@@ -21,5 +21,16 @@
     "config/**/*",
     ".umirc.ts",
     "typings.d.ts"
+  ],
+  "exclude": [
+    "node_modules",
+    "lib",
+    "es",
+    "dist",
+    "typings",
+    "**/__test__",
+    "test",
+    "docs",
+    "tests"
   ]
 }

+ 6 - 4
dashboard/typings.d.ts

@@ -1,8 +1,10 @@
 declare module '*.css';
 declare module '*.less';
-declare module "*.png";
+declare module '*.png';
 declare module '*.svg' {
-  export function ReactComponent(props: React.SVGProps<SVGSVGElement>): React.ReactElement
-  const url: string
-  export default url
+  export function ReactComponent(
+    props: React.SVGProps<SVGSVGElement>,
+  ): React.ReactElement;
+  const url: string;
+  export default url;
 }

+ 1 - 0
docker/.gitignore

@@ -0,0 +1 @@
+*.tar

+ 59 - 0
docker/Dockerfile

@@ -0,0 +1,59 @@
+FROM ubuntu:latest
+LABEL maintainer="Jeremy Zheng"
+
+ENV DEBIAN_FRONTEND noninteractive
+
+RUN apt update
+RUN apt -y upgrade
+RUN apt -y install apt-transport-https software-properties-common curl wget gnupg
+
+RUN apt -y install zsh git locales rsync openssh-client sshpass \
+    vim sudo tzdata pwgen curl zip unzip tree screen tmux \
+    build-essential \
+    php-cli php-fpm \
+    php-xml php-json php-imap php-intl \
+    php-mbstring php-bz2 php-zip php-curl \
+    php-gd php-imagick \
+    php-mysql php-pgsql php-sqlite3 php-redis
+RUN apt -y autoremove
+RUN apt -y clean
+
+RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
+RUN locale-gen
+RUN update-locale LANG=en_US.UTF-8
+RUN update-alternatives --set editor /usr/bin/vim.basic
+
+# deploy
+RUN useradd -m deploy -s /bin/zsh
+RUN passwd -l deploy
+RUN echo 'deploy ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/101-deploy
+
+USER deploy
+
+RUN mkdir -p $HOME/downloads $HOME/local
+
+# https://github.com/ohmyzsh/ohmyzsh
+RUN git clone https://github.com/ohmyzsh/ohmyzsh.git $HOME/.oh-my-zsh
+RUN cp $HOME/.oh-my-zsh/templates/zshrc.zsh-template $HOME/.zshrc
+RUN echo 'source $HOME/.profile' >> $HOME/.zshrc
+
+RUN echo 'term screen-256color' >> $HOME/.screenrc
+RUN echo 'startup_message off' >> $HOME/.screenrc
+RUN echo "defscrollback 10240" >> $HOME/.screenrc
+
+# https://github.com/nvm-sh/nvm
+RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | sh
+RUN sh -c ". $HOME/.profile \
+    && nvm install node"
+RUN sh -c ". $HOME/.profile \
+    && npm i yarn -g"
+RUN echo 'export PATH=$HOME/.yarn/bin:$PATH' >> $HOME/.profile
+
+RUN mkdir -p $HOME/.local/bin
+RUN wget https://getcomposer.org/download/latest-stable/composer.phar -O $HOME/.local/bin/composer
+RUN chmod +x $HOME/.local/bin/composer
+
+VOLUME /workspace
+WORKDIR /workspace
+
+CMD ["/bin/zsh", "-l"]

+ 21 - 0
docker/README.md

@@ -0,0 +1,21 @@
+# Usage for Ubuntu 20.10 and newer
+
+## Podman
+
+- Install
+
+```bash
+sudo apt -y install podman runc buildah skopeo
+```
+
+- Setup `/etc/containers/registries.conf`
+
+```text
+[registries.search]
+registries = ['quay.io', 'docker.io']
+```
+
+- Build(`cd docker && sh build.sh`) **OR** Import(`podman load -q -i mint-TIMESTAMP.tar`) image
+- Enjoy it!
+
+  ![start](documents/start.png)

+ 14 - 0
docker/build.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+export VERSION=$(date "+%4Y%m%d%H%M%S")
+export CODE="mint"
+
+buildah pull ubuntu:latest
+buildah bud --layers -t $CODE .
+podman save -o $CODE-$VERSION.tar $CODE
+
+echo 'done.'
+
+exit 0

BIN
docker/documents/start.png


+ 5 - 0
docker/start.sh

@@ -0,0 +1,5 @@
+#!/bin/sh
+
+podman run --rm -it --userns=keep-id \
+    --user=$(id -ur):$(id -gr) --network host \
+    --events-backend=file -v $PWD:/workspace:z mint

+ 18 - 0
documents/审校流程.md

@@ -0,0 +1,18 @@
+# 审校流程
+
+```mermaid
+graph LR;
+
+原始版私有--复刻-->编辑1私有库
+原始版私有--复刻-->编辑2私有库
+原始版私有--复刻-->编辑3私有库
+
+编辑1私有库 -- pr --> 润校channel
+编辑2私有库 -- pr --> 润校channel
+编辑3私有库 -- pr --> 润校channel
+
+润校channel -- 统稿人<br>merge --> 待定版
+
+待定版 -- 审稿人推送 --> IAPT正式版-公开
+
+```

Some files were not shown because too many files changed in this diff