Bladeren bron

Merge branch 'master' of https://github.com/iapt-platform/mint

bhikkhu-kosalla-china 4 jaren geleden
bovenliggende
commit
e99d4f4fe8

+ 4 - 2
app/article/function.php

@@ -25,7 +25,7 @@ class Article extends Table
 				return $output;
 			}
 		}
-        $query = "SELECT id,title,owner,summary,tag,status,create_time,modify_time FROM article WHERE id= ? ";
+        $query = "SELECT id,title,owner,subtitle,summary,tag,status,create_time,modify_time FROM article WHERE id= ? ";
         $stmt = $this->dbh->prepare($query);
         $stmt->execute(array($id));
         $output = $stmt->fetch(PDO::FETCH_ASSOC);
@@ -33,7 +33,9 @@ class Article extends Table
 			if($this->redis!==false){
 				$this->redis->hSet("article://".$id,"id",$output["id"]);
 				$this->redis->hSet("article://".$id,"title",$output["title"]);
-				$this->redis->hSet("article://".$id,"subtitle",$output["subtitle"]);
+				if(isset($output["subtitle"])){
+					$this->redis->hSet("article://".$id,"subtitle",$output["subtitle"]);
+				}
 				$this->redis->hSet("article://".$id,"summary",$output["summary"]);
 				$this->redis->hSet("article://".$id,"owner",$output["owner"]);
 				$this->redis->hSet("article://".$id,"tag",$output["tag"]);

+ 1 - 1
app/article/my_article_post.php

@@ -26,7 +26,7 @@ if($power<20){
 $_content = $_POST["content"];
 
 
-if($_POST["import"]=='on'){
+if(isset($_POST["import"]) && $_POST["import"]=='on'){
 	#导入自定义书
 	$custom_book = new CustomBook($redis);
 	$_lang = explode("_",$_POST["lang"]);

+ 14 - 3
app/db/table.php

@@ -78,8 +78,14 @@ class Table
 			$updateDate,
 			$where
 		);
-
-		return true;
+		if($this->medoo->error){
+			$this->result["ok"]=false;
+			$this->result["message"]=$this->medoo->error;
+			return false;
+		}else{
+			return true;
+		}
+		
 	}
 
 	public function _show($columns,$id){
@@ -88,7 +94,12 @@ class Table
 			$columns,
 			["id"=>$id]
 		);
-		$this->result["data"] = $output;
+		if($this->medoo->error){
+			$this->result["ok"]=false;
+			$this->result["message"]=$this->medoo->error;
+		}else{
+			$this->result["data"] = $output;
+		}
 		return $this->result;
 	}
 

+ 20 - 1
app/db/user.php

@@ -105,6 +105,11 @@ class User extends Table
 			echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
 			return;
 		}
+		//验证昵称有效性
+		if(!$this->isValidNickName($data["nickname"])){
+			echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
+			return;
+		}
 		$isExist = $this->medoo->has($this->table,["username"=>$data["username"]]);
 		if(!$isExist){
 			if(!$this->isValidEmail($data["email"])){
@@ -213,7 +218,8 @@ class User extends Table
 					$mail->Password   = Email["Password"];                               //SMTP password
 					$mail->SMTPSecure = Email["SMTPSecure"];            //Enable implicit TLS encryption
 					$mail->Port       = Email["Port"];                                    //TCP port to connect to 465; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`
-		
+					$mail->CharSet =  'UTF-8';
+					$mail->Encoding = 'base64';
 					//Recipients
 					$mail->setFrom(Email["From"], Email["Sender"]);
 					$mail->addAddress($email);     //Add a recipient Name is optional
@@ -313,6 +319,19 @@ class User extends Table
 		}
 		return true;
 	}
+	private function isValidNickName($nickname){
+		if(mb_strlen($nickname,"UTF-8")>32){
+			$this->result["ok"]=false;
+			$this->result["message"]="::nickname_too_long";
+			return false;
+		}
+		if(mb_strlen($nickname,"UTF-8")<1){
+			$this->result["ok"]=false;
+			$this->result["message"]="::nickname_too_short";
+			return false;
+		}
+		return true;
+	}
 	private function isValidEmail($email){	
 		$isValid = filter_var($email, FILTER_VALIDATE_EMAIL);
 		if($isValid===false){

+ 1 - 1
app/dict/turbo_split.php

@@ -232,7 +232,7 @@ function dict_lookup2($word){
 function dict_lookup($word)
 {
     if (strlen($word) <= 1) {
-        return 0;
+        return array(0,0);
     }
     global $case;
 	global $dbh;

+ 1 - 1
app/palicanon/palicanon.js

@@ -191,7 +191,7 @@ function render_chapter_head(chapter_info, parent) {
 		parent +
 		"')\">back</span></div>";
 	html += "</div>";
-	let link = "../reader/?view=chapter&book=" + chapter_info.book + "&para=" + chapter_info.paragraph;
+	let link = "../reader/?view=chapter&book=" + chapter_info.book + "&par=" + chapter_info.paragraph;
 	html += "<div class='title'>";
 	if (typeof chapter_info.trans_title == "undefined") {
 		html += "	<div class='title_1'><a href='" + link + "' target='_blank'>" + chapter_info.text + "</a></div>";

+ 2 - 2
app/pcdl/index.js

@@ -40,10 +40,10 @@ function index_load_collect_new() {
 				}
 				html += "</div>";
 				if (iterator.subtitle) {
-					html += "<div>" + iterator.subtitle + "</div>";
+					html += "<div class='subtitle'>" + iterator.subtitle + "</div>";
 				}
 				if (iterator.summary) {
-					html += "<div>" + iterator.summary + "</div>";
+					html += "<div class='summary'>" + iterator.summary + "</div>";
 				}
 
 				html += "<div style='margin-top:1em;'>" + iterator.username.nickname + "</div>";

+ 7 - 0
app/pcdl/index.php

@@ -74,6 +74,13 @@ require_once '../pcdl/html_head.php';
 		.article_right a {
 			color: var(--main-color);
 		}
+		.summary{
+			overflow: hidden;
+			text-overflow: ellipsis;
+			display: -webkit-box;
+			-webkit-line-clamp: 3;
+			-webkit-box-orient: vertical;
+		}
 
 		.title a,
 		.course_right title {

+ 31 - 0
app/public/js/comm.js

@@ -244,5 +244,36 @@ function str_diff(str1, str2) {
 	});
 	return output;
 }
+
+function testCJK(string){
+	/*
+	\u4e00-\u9fa5 (中文)
+	U+4E00至U+9FFF[1]
+	U+3400至U+4DBF[2](扩展A)
+	U+20000至U+2A6DF[3](扩展B)
+	U+2A700至U+2B73F[4](扩展C)
+	U+2B740至U+2B81F[5](扩展D)
+	U+2B820至U+2CEAF[6](扩展E)
+	U+F900至U+FAFF[7](兼容)
+	U+2F800至U+2FA1F[8](兼容补充)
+	U+2F00至U+2FDF[9](康熙部首)
+	U+2E80至U+2EFF[10](部首补充)
+	U+31C0至U+31EF[11](笔画)
+
+	\x3130-\x318F (韩文
+	\xAC00-\xD7A3 (韩文)
+	Unicode范围	U+AC00-U+D7A3,
+	U+1100-U+11FF,
+	U+3131-U+318E,
+	U+FFA1-U+FFDC
+
+	\u0800-\u4e00 (日文)ひらがな平仮名
+	U+4E00–U+9FBF 汉字; U+3040–U+309F 平假名; U+30A0–U+30FF 片假名
+	*/
+	reg = /[\u4e00-\u9fa5]+/;//cn
+	return reg.test(string);
+
+}
+
 //所有页面都需要在加载的的时候设置浏览器时区
 setTimeZone();

+ 5 - 0
app/public/lang/default.json

@@ -647,6 +647,11 @@
 		"username_too_short": "username too short",
 		"username_invaild_symbol": "username invaild symbol",
 		"password_invaild_symbol": "password invaild symbol",
+		"error_net_404": "Not Found",
+		"error_net_500": "Internal Server Error",
+		"error_net_timeout": "Timeout",
+		"error_net_abort": "abort",
+		"error_net_parsererror": "parser error",
 		"": ""
 	},
 	"grammastr": [

+ 5 - 0
app/public/lang/en.json

@@ -646,6 +646,11 @@
 		"username_too_short": "username too short",
 		"username_invaild_symbol": "username invaild symbol",
 		"password_invaild_symbol": "password invaild symbol",
+		"error_net_404": "Not Found",
+		"error_net_500": "Internal Server Error",
+		"error_net_timeout": "Timeout",
+		"error_net_abort": "abort",
+		"error_net_parsererror": "parser error",
 		"": ""
 	},
 	"grammastr": [

+ 5 - 0
app/public/lang/my.json

@@ -646,6 +646,11 @@
 		"username_too_short": "username too short",
 		"username_invaild_symbol": "username invaild symbol",
 		"password_invaild_symbol": "password invaild symbol",
+		"error_net_404": "Not Found",
+		"error_net_500": "Internal Server Error",
+		"error_net_timeout": "Timeout",
+		"error_net_abort": "abort",
+		"error_net_parsererror": "parser error",
 		"": ""
 	},
 	"grammastr": [

+ 5 - 0
app/public/lang/si.json

@@ -652,6 +652,11 @@
 		"username_too_short": "username too short",
 		"username_invaild_symbol": "username invaild symbol",
 		"password_invaild_symbol": "password invaild symbol",
+		"error_net_404": "Not Found",
+		"error_net_500": "Internal Server Error",
+		"error_net_timeout": "Timeout",
+		"error_net_abort": "abort",
+		"error_net_parsererror": "parser error",
 		"": ""
 	},
 	"grammastr": [

+ 5 - 0
app/public/lang/zh-cn.json

@@ -649,6 +649,11 @@
 		"username_too_short": "用户名过短",
 		"username_invaild_symbol": "用户名包含无效字符",
 		"password_invaild_symbol": "密码包含无效字符",
+		"error_net_404": "网页不存在",
+		"error_net_500": "服务器内部错误",
+		"error_net_timeout": "请求超时",
+		"error_net_abort": "放弃",
+		"error_net_parsererror": "数据解析错误",
 		"": ""
 	},
 	"grammastr": [

+ 5 - 0
app/public/lang/zh-tw.json

@@ -648,6 +648,11 @@
 		"username_too_short": "用戶名過短",
 		"username_invaild_symbol": "用戶名包含無效字符",
 		"password_invaild_symbol": "密碼包含無效字符",
+		"error_net_404": "網頁不存在",
+		"error_net_500": "服務器內部錯誤",
+		"error_net_timeout": "請求超時",
+		"error_net_abort": "放棄",
+		"error_net_parsererror": "數據解析錯誤",
 		"": ""
 	},
 	"grammastr": [

+ 1 - 1
app/reader/get_para.php

@@ -78,7 +78,7 @@ if ($FetchParInfo) {
 			}
             else{
 				$paraBegin = $FetchParInfo["parent"];
-				$query = "SELECT  chapter_len FROM 'pali_text'  WHERE book= ? AND paragraph= ?";
+				$query = "SELECT  level , parent, chapter_len,chapter_strlen FROM 'pali_text'  WHERE book= ? AND paragraph= ?";
 				$FetchParInfo = PDO_FetchRow($query, array($_book, $paraBegin));
             	$paraEnd = $paraBegin + $FetchParInfo["chapter_len"] - 1;
 			}

+ 8 - 0
app/reader/index.php

@@ -32,6 +32,10 @@ require_once "../pcdl/html_head.php";
 	if(isset($_GET["para"])){
 		echo "_reader_para='".$_GET["para"]."';";
 	}
+	if(isset($_GET["par"])){
+		#为了避免 &para被urlencode替换问题
+		echo "_reader_para='".$_GET["par"]."';";
+	}
 	if(isset($_GET["begin"])){
 		echo "_reader_begin='".$_GET["begin"]."';";
 	}
@@ -42,6 +46,10 @@ require_once "../pcdl/html_head.php";
 	if(isset($_GET["channal"])){
 		echo "_channal='".$_GET["channal"]."';";
 	}
+	if(isset($_GET["channel"])){
+		#纠正拼写错误
+		echo "_channal='".$_GET["channel"]."';";
+	}
 	if(isset($_GET["lang"])){
 		echo "_lang='".$_GET["lang"]."';";
 	}

+ 5 - 5
app/reader/reader.js

@@ -89,7 +89,7 @@ function reader_load() {
 					tocNextMenu +=
 						"<a href='../reader/?view=chapter&book=" +
 						_reader_book +
-						"&para=" +
+						"&par=" +
 						element.paragraph +
 						"'>" +
 						element.toc +
@@ -118,7 +118,7 @@ function reader_load() {
 							(element.level - firstLevel) +
 							"'><a href='../reader/?view=chapter&book=" +
 							_reader_book +
-							"&para=" +
+							"&par=" +
 							element.paragraph +
 							"&display=" +
 							_display +
@@ -172,7 +172,7 @@ function reader_draw_para_menu() {
 }
 
 function junp_to_para(book, para) {
-	let url = "../reader/?view=para&book=" + book + "&para=" + para + "&display=sent";
+	let url = "../reader/?view=para&book=" + book + "&par=" + para + "&display=sent";
 	location.assign(url);
 }
 
@@ -252,7 +252,7 @@ function set_channal(channalid) {
 		url += "&book=" + _reader_book;
 	}
 	if (_reader_para != -1) {
-		url += "&para=" + _reader_para;
+		url += "&par=" + _reader_para;
 	}
 	if (_reader_begin != -1) {
 		url += "&begin=" + _reader_begin;
@@ -289,7 +289,7 @@ function setMode(mode = "read") {
 		url += "&book=" + _reader_book;
 	}
 	if (_reader_para != -1) {
-		url += "&para=" + _reader_para;
+		url += "&par=" + _reader_para;
 	}
 	if (_reader_begin != -1) {
 		url += "&begin=" + _reader_begin;

+ 1 - 1
app/search/paliword.js

@@ -83,7 +83,7 @@ function render_word_result(worddata) {
 	html +=
 		"<a href='../reader/?view=chapter&book=" +
 		worddata.book +
-		"&para=" +
+		"&par=" +
 		worddata.para +
 		"&direction=col' target='_blank'>";
 	html += worddata.title + "</a></div>";

+ 8 - 0
app/studio/editor.php

@@ -259,6 +259,14 @@ else{$currDevice="computer";}
 		min-width: 1em;
 		min-height: 1.3em;
 	}
+
+	#word_mdf_parts_dropdown  a {
+		width: 100%;
+		display: inline-block;
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+	}
 	</style>
 	<link type="text/css" rel="stylesheet" href="css/print.css" media="print" />
 	<style id="display_set">

+ 21 - 36
app/studio/js/editor.js

@@ -220,9 +220,11 @@ function editor_windowsInit() {
 					g_book = item[1];
 					break;
 				case "para":
+				case "par":
 					g_para = item[1];
 					break;
 				case "channal":
+				case "channel":
 					g_channal = item[1];
 					break;
 			}
@@ -268,6 +270,7 @@ function editor_windowsInit() {
 			}
 			break;
 		case "openchannal":
+		case "openchannel":
 			editor_openChannal(g_book, g_para, g_channal);
 			break;
 		case "import":
@@ -3538,7 +3541,13 @@ function refreshPartMeaningSelect() {
 }
 //编辑窗口拆分意思复制到整体意思
 function copy_part_mean_to_mean() {
-	$("#input_meaning").val(removeFormulaB(g_arrPartMean.join(""), "[", "]"));
+	let meaning = g_arrPartMean.join("");
+	if(testCJK(meaning)){
+		$("#input_meaning").val(removeFormulaB(g_arrPartMean.join(""), "[", "]"));
+	}else{
+		$("#input_meaning").val(removeFormulaB(g_arrPartMean.join(" "), "[", "]"));
+	}
+	
 }
 //编辑窗口拆分意思下拉菜单
 function getMeaningMenuList(index, word) {
@@ -3554,7 +3563,7 @@ function getMeaningMenuList(index, word) {
 	if (part_mean_display_array.length - 1 >= index) {
 		currMeaningList.push(part_mean_display_array[index]);
 	} else {
-		currMeaningList.push("↓↓");
+		currMeaningList.push(" ");
 	}
 	for (const iterator of currMeaningList0) {
 		if (iterator != "") {
@@ -3574,51 +3583,27 @@ function getMeaningMenuList(index, word) {
 		currMean = g_arrPartMean[index];
 	}
 	if (currMean == "") {
-		currMean = "↓↓";
+		currMean = " ";
 	}
 	output += currMean + "</p>";
 
 	output += '<div class="case_dropdown-content" id=\'part_mean_menu_' + index + "'>";
 	//直列菜单
-	for (i in currMeaningList) {
-		output +=
-			"<a onclick='meaningPartChange(" +
-			index +
-			',"' +
-			currMeaningList[i] +
-			"\")'>" +
-			currMeaningList[i] +
-			"</a>";
-	}
-
-	//带字典名的菜单
-	/*
-	if(mDict[word]){
-		for(var j=0;j<mDict[word].length;j++){
-			//
-			output += "<div class='om_menu'>";
-			var dictName = mDict[word][j].dict_name;
-			if(dictName==""){
-				dictName="未知";
-			}
-			output += "<span>"+dictName+"</span>";
-			var currOM=mDict[word][j].mean.split("$");
-			for(var iMean in currOM){
-				if(currOM[iMean].length>0 && currOM[iMean]!="?"){
-					output +="<a  onclick='meaningPartChange("+index+",\""+currOM[iMean]+"\")'>"+currOM[iMean]+"</a>";
-				}
-			}
-			output +="</div>";			
+	output += "<a onclick='meaningPartLookup(\"" +word +"\")'>🔍" +gLocal.gui.dict +"</a>";	
+	for (const itMean of currMeaningList) {
+		if(itMean!="?"){
+			output += "<a onclick='meaningPartChange(" +index +	',"' +itMean +	"\")'>" +itMean +"</a>";					
 		}
+
 	}
-	else{
-		output += "未知";
-	}
-	*/
+
 	output += "</div>";
 	output += "</div>";
 	return output;
 }
+function meaningPartLookup(word){
+	window.open("../dict/index.php?builtin=true&theme=dark&key="+word,target="dict");
+}
 function getWordMeaningList(word) {
 	var currOM = "";
 	var arrOM = new Array();

+ 3 - 19
app/studio/js/render.js

@@ -1150,22 +1150,6 @@ function render_sent_tool_bar(elementBlock, begin) {
 	output += "<div class='sent_wbw_trans_bar'>";
 	let sentIdString = abook + "-" + aparagraph + "-" + iBegin + "-" + iEnd;
 	let sentIdStringLink = "{{" + sentIdString + "}}";
-	let sentReaderLink = "";
-	if (_display_sbs == 0) {
-		//逐段模式
-		sentReaderLink = "https://www.wikipali.org/app/reader/?view=para&book=" + abook + "&para=" + aparagraph;
-	} else {
-		//逐句模式
-		sentReaderLink =
-			"https://www.wikipali.org/app/reader/?view=sent&book=" +
-			abook +
-			"&para=" +
-			aparagraph +
-			"&begin=" +
-			iBegin +
-			"&end=" +
-			iEnd;
-	}
 
 	output += "<span style='flex: 7;display: flex;'>";
 	output += "<div style='background-color: silver;'>";
@@ -1189,11 +1173,11 @@ function render_sent_tool_bar(elementBlock, begin) {
 	let reader_open_link = "";
 	if (_display_sbs == 0) {
 		//逐段模式
-		reader_open_link = "../reader/?view=para&book=" + abook + "&para=" + aparagraph;
+		reader_open_link = "../reader/?view=para&book=" + abook + "&par=" + aparagraph;
 	} else {
 		//逐句模式
 		reader_open_link =
-			"../reader/?view=sent&book=" + abook + "&para=" + aparagraph + "&begin=" + iBegin + "&end=" + iEnd;
+			"../reader/?view=sent&book=" + abook + "&par=" + aparagraph + "&begin=" + iBegin + "&end=" + iEnd;
 	}
 	output +=
 		"<button class='icon_btn'  onclick=\"window.open('" +
@@ -1528,7 +1512,7 @@ function renderWordParBlockInner(elementBlock) {
 				output +=
 					"<button class='icon_btn'  onclick=\"window.open('../reader/?view=sent&book=" +
 					book +
-					"&para=" +
+					"&par=" +
 					paragraph +
 					"&begin=" +
 					nextBegin +

+ 1 - 1
app/studio/js/wizard.js

@@ -650,7 +650,7 @@ function explorer_show_res_list(book,para){
 			}
 			else{
 				arrResData[i].enable=true;
-				var read_link="../reader/?view=para&book="+arrResData[i].book+"&channal="+arrResData[i].album_id+"&para="+arrResData[i].paragraph;
+				var read_link="../reader/?view=para&book="+arrResData[i].book+"&channal="+arrResData[i].album_id+"&par="+arrResData[i].paragraph;
 				var check="<input type='checkbox' id='res_check_"+resCount+"' checked onclick=\"set_res_enable(this,"+i+")\" />";
 				html+=check+"["+arrResData[i].type+"]<a href='"+read_link+"' target='_blank'>"+arrResData[i].title+"</a>-"+arrResData[i].author;
 				resCount++;

+ 5 - 5
app/studio/module/editor_palicannon/language/en.js

@@ -148,11 +148,11 @@ var local_palicannon_index=[
 { "name":"t-abh6" , "row":"177" , "id":"p177" , "folder":"abh06t.nrf" , "title":"Abhidhammāvatāra" , "c1":"abhidhamma" , "c2":"añña" , "c3":"Abhidhammāvatāra" , "c4":"" },
 { "name":"t-abh8" , "row":"179" , "id":"p179" , "folder":"abh08t.nrf" , "title":"Abhidhammāvatāra-ṭīkā" , "c1":"abhidhamma" , "c2":"añña" , "c3":"Abhidhammāvatāra" , "c4":"" },
 { "name":"t-abh7" , "row":"178" , "id":"p178" , "folder":"abh07t.nrf" , "title":"Abhidhammatthasaṅgaho" , "c1":"abhidhamma" , "c2":"añña" , "c3":"Abhidhammatthasaṅgaha" , "c4":"" },
-{ "name":"a-vis1" , "row":"64" , "id":"p64" , "folder":"e0101n.mul" , "title":"Visuddhimaggo(Paṭhamo bhāgo)" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
-{ "name":"a-vis2" , "row":"65" , "id":"p65" , "folder":"e0102n.mul" , "title":"Visuddhimaggo(Dutiyo bhāgo)" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
-{ "name":"a-vis3" , "row":"66" , "id":"p66" , "folder":"e0103n.att" , "title":"Visuddhimagga-mahāṭīkā(Paṭhamo bhāgo)" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
-{ "name":"a-vis4" , "row":"67" , "id":"p67" , "folder":"e0104n.att" , "title":"Visuddhimagga-mahāṭīkā(Dutiyo bhāgo)" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
-{ "name":"a-vis5" , "row":"68" , "id":"p68" , "folder":"e0105n.nrf" , "title":"Visuddhimagga nidānakathā" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
+{ "name":"a-vis1" , "row":"64" , "id":"p64" , "folder":"e0101n.mul" , "title":"Visuddhimaggo(Paṭhamo bhāgo)" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
+{ "name":"a-vis2" , "row":"65" , "id":"p65" , "folder":"e0102n.mul" , "title":"Visuddhimaggo(Dutiyo bhāgo)" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
+{ "name":"a-vis3" , "row":"66" , "id":"p66" , "folder":"e0103n.att" , "title":"Visuddhimagga-mahāṭīkā(Paṭhamo bhāgo)" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
+{ "name":"a-vis4" , "row":"67" , "id":"p67" , "folder":"e0104n.att" , "title":"Visuddhimagga-mahāṭīkā(Dutiyo bhāgo)" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
+{ "name":"a-vis5" , "row":"68" , "id":"p68" , "folder":"e0105n.nrf" , "title":"Visuddhimagga nidānakathā" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
 { "name":"a-sam1" , "row":"39" , "id":"p39" , "folder":"e0901n.nrf" , "title":"Dīghanikāye" , "c1":"añña" , "c2":"saṅgayana-puccha vissajjanā" , "c3":"" , "c4":"" },
 { "name":"a-sam2" , "row":"40" , "id":"p40" , "folder":"e0902n.nrf" , "title":"Majjhimanikāya" , "c1":"añña" , "c2":"saṅgayana-puccha vissajjanā" , "c3":"" , "c4":"" },
 { "name":"a-sam3" , "row":"41" , "id":"p41" , "folder":"e0903n.nrf" , "title":"Saṃyuttanikāye" , "c1":"añña" , "c2":"saṅgayana-puccha vissajjanā" , "c3":"" , "c4":"" },

+ 5 - 5
app/studio/module/palicannon/language/en.js

@@ -148,11 +148,11 @@ var local_palicannon_index=[
 { "name":"t-abh7" , "id":"178" , "folder":"abh07t.nrf" , "title":"Abhidhammatthasaṅgaho" , "c1":"ṭīkā" , "c2":"abhidhamma" , "c3":"" , "c4":"" },
 { "name":"t-abh8" , "id":"179" , "folder":"abh08t.nrf" , "title":"Paṭhamo paricchedo" , "c1":"ṭīkā" , "c2":"abhidhamma" , "c3":"" , "c4":"" },
 { "name":"t-abh9" , "id":"180" , "folder":"abh09t.nrf" , "title":"Abhidhammamātikāpāḷi" , "c1":"ṭīkā" , "c2":"abhidhamma" , "c3":"" , "c4":"" },
-{ "name":"a-vis1" , "id":"64" , "folder":"e0101n.mul" , "title":"Visuddhimaggo(Paṭhamo bhāgo)" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
-{ "name":"a-vis2" , "id":"65" , "folder":"e0102n.mul" , "title":"Visuddhimaggo(Dutiyo bhāgo)" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
-{ "name":"a-vis3" , "id":"66" , "folder":"e0103n.att" , "title":"Visuddhimagga-mahāṭīkā(Paṭhamo bhāgo)" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
-{ "name":"a-vis4" , "id":"67" , "folder":"e0104n.att" , "title":"Visuddhimagga-mahāṭīkā(Dutiyo bhāgo)" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
-{ "name":"a-vis5" , "id":"68" , "folder":"e0105n.nrf" , "title":"Visuddhimagga nidānakathā" , "c1":"añña" , "c2":"visddhimaga" , "c3":"" , "c4":"" },
+{ "name":"a-vis1" , "id":"64" , "folder":"e0101n.mul" , "title":"Visuddhimaggo(Paṭhamo bhāgo)" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
+{ "name":"a-vis2" , "id":"65" , "folder":"e0102n.mul" , "title":"Visuddhimaggo(Dutiyo bhāgo)" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
+{ "name":"a-vis3" , "id":"66" , "folder":"e0103n.att" , "title":"Visuddhimagga-mahāṭīkā(Paṭhamo bhāgo)" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
+{ "name":"a-vis4" , "id":"67" , "folder":"e0104n.att" , "title":"Visuddhimagga-mahāṭīkā(Dutiyo bhāgo)" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
+{ "name":"a-vis5" , "id":"68" , "folder":"e0105n.nrf" , "title":"Visuddhimagga nidānakathā" , "c1":"añña" , "c2":"visuddhimagga" , "c3":"" , "c4":"" },
 { "name":"a-sam1" , "id":"39" , "folder":"e0901n.nrf" , "title":"Dīghanikāye" , "c1":"añña" , "c2":"saṅgayana-puccha vissajjanā" , "c3":"" , "c4":"" },
 { "name":"a-sam2" , "id":"40" , "folder":"e0902n.nrf" , "title":"Majjhimanikāya" , "c1":"añña" , "c2":"saṅgayana-puccha vissajjanā" , "c3":"" , "c4":"" },
 { "name":"a-sam3" , "id":"41" , "folder":"e0903n.nrf" , "title":"Saṃyuttanikāye" , "c1":"añña" , "c2":"saṅgayana-puccha vissajjanā" , "c3":"" , "c4":"" },

+ 0 - 50
app/studio/plugin/system_dict/gui.html

@@ -9,55 +9,5 @@
 			</style>
 			<div id="dict_ref_search" style="height: 100%;padding:0;">
 				<iframe id="dict" src="../dict/index.php?builtin=true&theme=dark" name="dict" title="wikipali" style="width:100%;height:100%;border: none;"></iframe>
-				<!--
-				<div id="right_tool_bar_title" >
-					<ul id="id_select_modyfy_type" class="common-tab" >
-						<button class="res_button" style="padding: 0" onclick="editor_show_right_tool_bar(false)">
-							<svg class="button_icon"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="svg/icon.svg#ic_input"></use></svg>
-						</button>	
-						
-						<button onclick="dict_search('_home_')">Home</button>
-						<button onclick="dict_turbo_split()">Turbo Split</button>
-						<a href="setting.php?item=dictionary" target="_blank">
-							<svg class="icon">
-								<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="svg/icon.svg#ic_settings"></use>
-							</svg>
-						</a>
-					</ul>
-
-					<div>
-						<div id="dict_ref_search_head">
-							<div id="dict_ref_search_input_div">
-								<div id="dict_ref_search_input_head">
-									<table>
-										<tr>
-											<td>
-												<div class="case_dropdown">
-													<svg class="button_icon"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="svg/icon.svg#ic_more"></use></svg>
-													<div id="dict_ref_dict_link" class="case_dropdown-content">
-														<a onclick="">[dict]</a>
-													</div>
-												</div>
-											</td>
-											<td style="width: 95%;">
-												<input id="dict_ref_search_input" type="input"  onkeyup="dict_input_keyup(event,this)">
-											</td>
-										</tr>
-									</table>
-								</div>
-
-								<div>
-									<div id="input_parts"></div>
-									<div id="dict_word_auto_split"></div>
-								</div>
-							</div>
-						</div>
-
-					</div>
-							
-				</div>
-				<div id="dict_ref_search_result">
-				</div>
-			-->
 			</div>
 			

+ 3 - 3
app/term/note.js

@@ -524,13 +524,13 @@ function note_ref_init() {
 	$("chapter").click(function () {
 		let bookid = $(this).attr("book");
 		let para = $(this).attr("para");
-		window.open("../reader/?view=chapter&book=" + bookid + "&para=" + para, "_blank");
+		window.open("../reader/?view=chapter&book=" + bookid + "&par=" + para, "_blank");
 	});
 
 	$("para").click(function () {
 		let bookid = $(this).attr("book");
 		let para = $(this).attr("para");
-		window.open("../reader/?view=para&book=" + bookid + "&para=" + para, "_blank");
+		window.open("../reader/?view=para&book=" + bookid + "&par=" + para, "_blank");
 	});
 }
 /*
@@ -1806,7 +1806,7 @@ function copy_ref(book, para, begin, end) {
 }
 
 function goto_nissaya(book, para, begin = 0, end = 0) {
-	window.open("../nissaya/index.php?book=" + book + "&para=" + para + "&begin=" + begin + "&end=" + end, "nissaya");
+	window.open("../nissaya/index.php?book=" + book + "&par=" + para + "&begin=" + begin + "&end=" + end, "nissaya");
 }
 function edit_in_studio(book, para, begin, end) {
 	wbw_channal_list_open(book, [para]);

+ 1 - 1
app/term/related_para.js

@@ -49,7 +49,7 @@ function related_para_dlg_render(para) {
 			output +=
 				"<a href='../reader/?view=chapter&book=" +
 				paraList[0].book +
-				"&para=" +
+				"&par=" +
 				paraList[0].para +
 				"' target='_blank'>" +
 				iterator.title +

+ 10 - 0
app/term/term.css

@@ -981,4 +981,14 @@ pali>p {
 
 .sent_mode>div>p {
     border-bottom: 0.5em solid var(--btn-color);
+}
+
+
+.circle_num { border: 1px solid var(--border-line-color);
+    border-radius: 99px;
+    line-height: 20px;
+    width: 22px;
+    text-align: center;
+    display: inline-block;
+    margin-left: 5px;
 }

+ 15 - 6
app/ucenter/forgot_pwd.php

@@ -18,6 +18,9 @@ require_once "../public/function.php";
 		<script src="../public/js/comm.js"></script>
 		<script src="../studio/js/jquery-3.3.1.min.js"></script>
 		<script src="../studio/js/fixedsticky.js"></script>
+		<script>
+		<?php require_once '../public/load_lang_js.php'; ?>
+		</script>
 		<style>
 		#login_body{
 			display: flex;
@@ -191,7 +194,7 @@ require_once "../public/function.php";
 
 					</form>
 					<div id="button_area">
-						<button  onclick="submit()" style="background-color: var(--link-hover-color);border-color: var(--link-hover-color);" >
+						<button id="send"  onclick="submit()" style="background-color: var(--link-hover-color);border-color: var(--link-hover-color);" >
 						<?php echo $_local->gui->continue; ?>
 						</button>
 					</div>
@@ -206,6 +209,7 @@ require_once "../public/function.php";
 	
 	function submit(){
 		$("#message").text("正在发送...");
+		$(this).text("正在发送...");
 		$(this).prop("disabled",true);
 	$.getJSON(
 		"../api/user.php",
@@ -222,16 +226,19 @@ require_once "../public/function.php";
 			$("#message").addClass("form_error");
 			//发送失败enable发送按钮
 			$(this).prop("disabled",false);
+			$(this).text("再次发送");
 		}
 		}).fail(function(jqXHR, textStatus, errorThrown){
-			$("#message").removeClass("form_error");
-			$("#message").text(textStatus);	
-			//发送失败enable发送按钮
-			$(this).prop("disabled",false);		
+			$("#message").addClass("form_error");
 			switch (textStatus) {
 				case "timeout":
+					$("#message").text(gLocal.gui["error_net_timeout"]);	
+					//发送失败enable发送按钮
+					$(this).prop("disabled",false);
+					$(this).text("再次发送");
 					break;
 				case "error":
+					$("#message").text(gLocal.gui["error_net_"+jqXHR.status]);
 					switch (jqXHR.status) {
 						case 404:
 							break;
@@ -242,8 +249,10 @@ require_once "../public/function.php";
 					}
 					break;
 				case "abort":
+					$("#message").text(gLocal.gui["error_net_abort"]);	
 					break;
-				case "parsererror":			
+				case "parsererror":
+					$("#message").text(gLocal.gui["error_net_parsererror"]);	
 					console.log("delete-parsererror",jqXHR.responseText);
 					break;
 				default:

+ 18 - 5
app/ucenter/reset.php

@@ -24,6 +24,7 @@ if (!isset($_GET["token"])) {
 		<script src="../public/js/comm.js"></script>
 		<script src="../studio/js/jquery-3.3.1.min.js"></script>
 		<script src="../studio/js/fixedsticky.js"></script>
+		<script src="../ucenter/sign.js"></script>
 		<style>
 		#login_body{
 			display: flex;
@@ -191,7 +192,7 @@ if (!isset($_GET["token"])) {
 					<div>
 						<div>
 							<span id='tip_username' class='form_field_name'><?php echo $_local->gui->account; ?></span>
-							<input type="input" id="username" name="username"  value="" />
+							<input type="input" maxlength="32" id="username" name="username"  value="" />
 						</div>
 						<div id="error_username" class="form_error"> </div>
 						<div class="form_help"></div>
@@ -200,8 +201,8 @@ if (!isset($_GET["token"])) {
 					<div>
 						<div>
 							<span id='tip_password' class='form_field_name'><?php echo $_local->gui->password; ?></span>
-							<input type="password" id="password" name="password" placeholder="密码" value="" />
-							<input type="password" id="repassword" name="repassword" placeholder="再次输入密码" value="" />
+							<input type="password" id="password" maxlength="32" name="password" placeholder="密码" value="" />
+							<input type="password" id="repassword" maxlength="32" name="repassword" placeholder="再次输入密码" value="" />
 						</div>
 						<div class="form_help">至少6个字符</div>
 						<div id="error_password" class="form_error"></div>
@@ -210,7 +211,7 @@ if (!isset($_GET["token"])) {
 					<input type="hidden"  id="token" name="token" value="<?php echo $_REQUEST["token"]; ?>" />
 				</form>
 				<div id="button_area">
-					<button  onclick="submit()" style="background-color: var(--link-hover-color);border-color: var(--link-hover-color);" >
+					<button  onclick="reset_submit()" style="background-color: var(--link-hover-color);border-color: var(--link-hover-color);" >
 					<?php echo $_local->gui->continue; ?>
 					</button>
 				</div>	
@@ -226,7 +227,19 @@ if (!isset($_GET["token"])) {
 	<script>
 	login_init();
 
-	function submit(){
+	function reset_submit(){
+		let hasError = false;
+		if($("#password").val()!==$("#repassword").val()){
+		$("#error_password").text("两次密码输入不一致");
+			hasError = true;
+		}
+		if(isValidPassword($("#password").val())==false){
+			$("#error_password").text("密码包含无效字符。 ' / , 空格 '");
+			hasError = true;
+		}
+		if(hasError){
+			return;
+		}
 		$.ajax({
 			type: 'POST',
 			url:"../api/user.php?_method=reset_pwd",

+ 1 - 1
app/ucenter/reset_pwd_letter.html

@@ -4,7 +4,7 @@ wikipali reset password
 如果您没有进行过此操作请忽略这个邮件。
 </p>
 <p>
-点击此链接重置您的wikipali账号的密码。
+点击此链接重置您的wikipali账号的密码。此链接一小时内有效。
 <a href="%ResetLink%">%ResetString%</a>
 </p>
 <p>

+ 34 - 6
app/ucenter/sign.js

@@ -1,12 +1,40 @@
+function isValidPassword(str){
+	let patt=new RegExp(/\s|\//);
+	if(patt.test(str)){
+		return false;
+	}else{
+		return true;
+	}
+}
+function isValidUserName(str){
+	let patt=new RegExp(/@|\s|\//);
+	if(patt.test(str)){
+		return false;
+	}else{
+		return true;
+	}
+}
 function submit(){
+	let hasError = false;
 	if($("#password").val()!==$("#repassword").val()){
 		$("#error_password").text("两次密码输入不一致");
-		return;
+		hasError = true;
+	}
+	if(isValidPassword($("#password").val())==false){
+		$("#error_password").text("密码包含无效字符。  / 空格 ");
+		hasError = true;
+	}
+
+	if(isValidUserName($("#username").val())==false){
+		$("#error_password").text("用户名包含无效字符。@  / 空格 ");
+		hasError = true;
 	}
-	let nickname = $("#nickname").val();
+
+	let nickname = $("#nickname").val();	
 	if( nickname ==""){
 		nickname = $("#username").val();
 	}
+
 	let lang = $("#lang").val();
 	if(lang=="zh-cn"){
 		lang = "zh-hans";
@@ -14,6 +42,9 @@ function submit(){
 	if(lang == "zh-tw"){
 		lang = "zh-hant";
 	}
+	if(hasError){
+		return;
+	}
 	$.ajax({
 		type: 'POST',
 		url:"../api/user.php?_method=create",
@@ -23,20 +54,17 @@ function submit(){
 			username:$("#username").val(),
 			password:$("#password").val(),
 			email:$("#email").val(),
-			nickname:$("#nickname").val(),
+			nickname:nickname,
 			lang:$("#lang").val()
 		}),
 		dataType:"json"
 		}).done(function (data) {
-			
 			if(data.ok){
 				$("#form_div").hide();
 				$("#message").removeClass("form_error");
 				$("#message").html("注册成功。<a href='index.php?op=login'>"+gLocal.gui.login+"</a>");
-
 			}else{
 				$("#message").addClass("form_error");
-
 				$("#message").text(ConvertServerMsgToLocalString(data.message));
 			}
 	}).fail(function(jqXHR, textStatus, errorThrown){

+ 1 - 2
app/ucenter/sign_up.php

@@ -21,7 +21,7 @@ require_once "../redis/function.php";
 		<script src="../ucenter/sign.js"></script>
 		<script>
 		<?php require_once '../public/load_lang_js.php'; ?>
-	</script>
+		</script>
 		<style>
 		#login_body{
 			display: flex;
@@ -256,7 +256,6 @@ require_once "../redis/function.php";
 								<input type="input" id="nickname"  maxlength="32"  name="nickname" placehoder="" value="" />
 							</div>
 							<div class="form_help">
-							<?php echo $_local->gui->name_for_show; ?>
 							</div>
 							<div id="error_password" class="form_error"> </div>
 						</div>

+ 6 - 2
app/uwbw/create_wbw.php

@@ -4,6 +4,8 @@
 require_once '../path.php';
 require_once "../public/_pdo.php";
 require_once "../public/function.php";
+require_once "../channal/function.php";
+require_once "../redis/function.php";
 define("MAX_LETTER" ,20000);
 
 $output["status"]=0;
@@ -75,6 +77,8 @@ $dbh_tpl->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
 $db_wbw = ""._FILE_DB_USER_WBW_;
 $dbh_wbw= new PDO($db_wbw, "", "");
 $dbh_wbw->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+$channelClass = new Channal(redis_connect());
+$channelInfo = $channelClass->getChannal($_channel);
 
 foreach ($_para as $key => $para) {
     # code...
@@ -94,8 +98,8 @@ foreach ($_para as $key => $para) {
                                          $_book,
                                          $para,
                                          "",
-                                         $_POST["lang"],
-                                         1,
+                                         $channelInfo["lang"],
+                                         $channelInfo["status"],
                                          mTime(),
                                          mTime()
                                         );

+ 63 - 14
app/uwbw/wbw_channal_list.js

@@ -1,14 +1,34 @@
 var _wbw_channel;
 function wbw_channal_list_init() {
-	$("body").append(
-		'<div id="wbw_channal_list_dlg" title=' +
-			gLocal.gui.open +
-			gLocal.gui.wbw +
-			' style="overflow-y:scroll;"><div id="wbw_channal_list_dlg_content"></div></div>'
-	);
+	let channelListHtml = "";
+	let style = "<style>";
+	style += "#wbw_channal_list_dlg_content .ui-widget-content{border:unset;} ";
+	style += "#wbw_channal_list_dlg_content .ui-widget-header{background:unset;border:unset;border-bottom: 1px solid #dddddd;} ";
+	style += "</style>";
+	channelListHtml += '<div id="wbw_channal_list_dlg" title=' + gLocal.gui.open + gLocal.gui.wbw + '>';
+	channelListHtml += style;
+	channelListHtml += '<div id="wbw_channal_list_dlg_content">';
+	channelListHtml += '<div id="tabs">';
+	channelListHtml += '<ul>';
+    channelListHtml += '<li><a href="#tabs-1">我的<span id="my-num" class="circle_num">3</span></a></li>';
+    channelListHtml += '<li><a href="#tabs-2">协作<span id="co-num"  class="circle_num">2</span></a></li>';
+    channelListHtml += '<li><a href="#tabs-3">网络公开<span id="pu-num"  class="circle_num">1</span></a></li>';
+	channelListHtml += '</ul>';
+	channelListHtml += '<div id="tabs-1">';
+	channelListHtml += '</div>';
+	channelListHtml += '<div id="tabs-2">';
+	channelListHtml += '</div>';
+	channelListHtml += '<div id="tabs-3">';
+	channelListHtml += '</div>';
+	channelListHtml += '</div>';
+	channelListHtml += '</div>';
+	channelListHtml += '</div>';
+
+	$("body").append(channelListHtml);
 	$("#wbw_channal_list_dlg").dialog({
 		autoOpen: false,
-		width: 550,
+		width: 700,
+		height:650,
 		maxHeight: $(window).height()*0.7,
 		buttons: [
 			{
@@ -19,6 +39,7 @@ function wbw_channal_list_init() {
 			},
 		],
 	});
+	$( "#tabs" ).tabs();
 }
 
 function wbw_channal_list_open(book, paralist) {
@@ -31,11 +52,18 @@ function wbw_channal_list_open(book, paralist) {
 		function (data) {
 			_wbw_channel = JSON.parse(data);
 			if (_wbw_channel.status == 0) {
-				let html = "";
+				let htmlMy = "";
+				let htmlCollaborate = "";
+				let htmlPublic = "";
+				let myNum = 0;
+				let coNum = 0;
+				let puNum = 0;
+
 				for (let index = 0; index < _wbw_channel.data.length; index++) {
 					const element = _wbw_channel.data[index];
+					let html = "";
 					html += "<div style='display:flex;line-height: 2.5em;border-bottom: 1px solid gray;'>";
-					html += "<span style='flex:4'>";
+					html += "<span style='flex:3'>";
 					let style = "";
 					let text = "";
 					if (parseInt(element.wbw_para) > 0) {
@@ -61,7 +89,7 @@ function wbw_channal_list_open(book, paralist) {
 					html += "</span>";
 					html += "<span  style='flex:1'>" + (index + 1) + "</span>";
 					html += "<span style='flex:5'>" + element.name + "</span>";
-					html += "<span style='flex:1'>";
+					html += "<span style='flex:2'>";
 					let power = [
 						{ id: 10, note: gLocal.gui.viewer },
 						{ id: 20, note: gLocal.gui.editor },
@@ -73,12 +101,34 @@ function wbw_channal_list_open(book, paralist) {
 						}
 					}
 					html += "</span>";
-					html += "<span style='flex:2'>" + element.lang + "</span>";
+					html += "<span style='flex:2'>";
+					html += element.user.nickname;
+					html += "</span>";
+					html += "<span style='flex:1;text-align: right;'>" + element.lang + "</span>";
 					html += "<span style='flex:2;display:none;'>" + element.wbw_para + "/" + element.count + "</span>";
 					html += "</div>";
+					switch (element.type) {
+						case "my":
+							htmlMy +=html;
+							myNum++;
+							break;
+						case "collaborate":
+							htmlCollaborate +=html;
+							coNum++
+							break;	
+						case "public":
+							htmlPublic +=html;
+							puNum++
+							break;		
+					}
 				}
 
-				$("#wbw_channal_list_dlg_content").html(html);
+				$("#tabs-1").html(htmlMy);
+				$("#tabs-2").html(htmlCollaborate);
+				$("#tabs-3").html(htmlPublic);
+				$("#my-num").text(myNum);
+				$("#co-num").text(coNum);
+				$("#pu-num").text(puNum);
 				$("#wbw_channal_list_dlg").dialog("open");
 			} else {
 				ntf_show(_wbw_channel.error);
@@ -100,12 +150,11 @@ function wbw_create(index) {
 		function (data) {
 			let msg = JSON.parse(data);
 			if (msg.status == 0) {
-				$("#wbw_channal_list_dlg_content").html("正在打开编辑窗口");
 				let book = msg.book;
 				let paralist = msg.para.join(",");
 				let channel = msg.channel;
 				let url =
-					"../studio/editor.php?op=openchannal&book=" + book + "&para=" + paralist + "&channal=" + channel;
+					"../studio/editor.php?op=openchannel&book=" + book + "&par=" + paralist + "&channel=" + channel;
 				window.open(url, "_blank");
 				$("#wbw_channal_list_dlg").dialog("close");
 			} else {

+ 7 - 4
app/uwbw/wbw_channel_list.php

@@ -4,6 +4,7 @@ require_once "../public/_pdo.php";
 require_once "../public/function.php";
 require_once '../share/function.php';
 require_once '../channal/function.php';
+require_once '../ucenter/function.php';
 require_once '../redis/function.php';
 
 $redis = redis_connect();
@@ -30,14 +31,14 @@ $params[] = $_book;
 
 #查重复
 $channelList = array();
-
+#先查自己的
 PDO_Connect(_FILE_DB_CHANNAL_);
 $query = "SELECT id FROM channal WHERE owner = ? and status>0 LIMIT 0,100";
 $FetchChannal = PDO_FetchAll($query, array($_COOKIE["userid"]));
 
 foreach ($FetchChannal as $key => $value) {
 	# code...
-	$channelList[$value["id"]]=array("power"=>30);
+	$channelList[$value["id"]]=array("power"=>30,"type"=>"my");
 }
 
 # 找协作的
@@ -50,7 +51,7 @@ foreach ($coop_channal as $key => $value) {
 		}
 	}
 	else{
-		$channelList[$value["res_id"]]=array("power"=>(int)$value["power"]);
+		$channelList[$value["res_id"]]=array("power"=>(int)$value["power"],"type"=>"collaborate");
 	}
 }
 
@@ -61,11 +62,12 @@ $publicChannel = PDO_FetchAll($query, $params);
 foreach ($publicChannel as $key => $channel) {
 	# code...
 	if(!isset($channelList[$channel["channal"]])){
-		$channelList[$channel["channal"]]=array("power"=>10);
+		$channelList[$channel["channal"]]=array("power"=>10,"type"=>"public");
 	}
 }
 
 $channelInfo = new Channal($redis);
+$userInfo = new UserInfo();
 $i = 0;
 $outputData = array();
 
@@ -81,6 +83,7 @@ foreach ($channelList as $key => $row) {
     $channelList[$key]["id"] = $info["id"];
     $channelList[$key]["name"] = $info["name"];
     $channelList[$key]["lang"] = $info["lang"];
+	$channelList[$key]["user"] = $userInfo->getName($info["owner"]);
 	$outputData[]=$channelList[$key];
 }
 

+ 253 - 0
app/widget/term_input.html

@@ -0,0 +1,253 @@
+<!--键入[[显示术语下拉菜单-->
+<html>
+	<body>
+		<style>
+			.textarea,
+			textarea {
+				padding: 0;
+				font-family: inherit;
+				width: 100%;
+				height: 100px;
+				resize: vertical;
+				font-size: 14px;
+				line-height: 1;
+				border: 1px solid #ddd;
+				white-space: pre-wrap;
+				word-break: break-all;
+				z-index: 1;
+			}
+			#text_shadow{
+				position: absolute;
+				width: 300px;
+				visibility: hidden;
+			}
+			.cursor{
+				position: absolute;
+				border-left: 1px solid #000;
+			}
+			#menu{
+				width: 200px;
+				height:300px;
+				background-color: aqua;
+				box-shadow: #000;
+				position:absolute;
+				display: none;
+			}
+			#menu ul{
+				list-style-type: none;
+    margin: 0;
+    padding: 0;
+			}
+			#menu .focus{
+				color:red;
+			}
+		</style>
+
+<h2>术语输入测试</h2>
+<div style='width:300px;position: relative;'>
+<div id="menu"></div>
+<div class="textarea" id="text_shadow" >
+前端路迹<span class="cursor">&nbsp;</span>
+qinshenxue.com
+</div>
+<textarea>
+前端路迹
+qinshenxue.com
+</textarea>
+</div>
+
+<script>
+	var menuFocusIndex=0;
+	var data=["amanussa","anadhiṭṭhita","anantarāya","anissaṭṭha","aniyata","antaravāsaka"];
+	var textarea = document.querySelector('textarea');
+	textarea.onkeydown = function (e) {
+		textarea.clientHeight
+		let menu = document.querySelector('#menu');
+		switch (e.key) {
+			case "ArrowDown"://down arrow
+				if(menu.style.display=="block"){
+					menuFocusIndex++;
+					if(menuFocusIndex>5){
+						menuFocusIndex=5;
+					}
+					menu.innerHTML=renderMenu({focus:menuFocusIndex});
+					return false;					
+				}
+				break;
+			case "ArrowUp"://up arrow
+				if(menu.style.display=="block"){
+					menuFocusIndex--;
+					if(menuFocusIndex<0){
+						menuFocusIndex=0;
+					}
+					menu.innerHTML=renderMenu({focus:menuFocusIndex});
+					return false;					
+				}
+			break;
+			case "Enter":
+				if(menu.style.display=="block"){
+					let value = textarea.value;
+					let selectionStart = textarea.selectionStart;
+					let str1 = value.slice(0, selectionStart)
+					let str2 = value.slice(selectionStart);
+					textarea.value = str1+data[menuFocusIndex]+"]]"+str2;
+					menu.style.display="none";
+					return false;
+				}
+				else{
+					if(!e.shiftKey){
+						return false;
+					}
+				}
+				
+				break;
+			case "Escape":
+				e.currentTarget.value="";
+				break;
+			default:
+				break;
+		}
+	}
+	textarea.onkeyup = function (e) {
+		let value = textarea.value
+		let selectionStart = textarea.selectionStart
+		let str1 = value.slice(0, selectionStart)
+		let str2 = value.slice(selectionStart)
+		let textNode1 = document.createTextNode(str1)
+		let textNode2 = document.createTextNode(str2)
+		let cursor = document.createElement('span')
+		cursor.innerHTML = '&nbsp;'
+		cursor.setAttribute('class','cursor')
+		let mirror = document.querySelector('.textarea')
+		mirror.innerHTML = ''
+		mirror.appendChild(textNode1)
+		mirror.appendChild(cursor)
+		mirror.appendChild(textNode2)
+		let menu = document.querySelector('#menu');		
+		if(str1.slice(-2)=="[[" && menu.style.display!="block"){
+			menuFocusIndex=0;
+			menu.innerHTML=renderMenu({focus:0});
+			menu.style.display="block";
+			menu.style.top=cursor.offsetTop+14;
+			menu.style.left=cursor.offsetLeft;
+		}
+
+		if(e.key=="Escape"){
+			menu.style.display="none";
+		}
+		
+		console.log(keynum);
+		console.log(cursor.offsetLeft,cursor.offsetTop)
+	}
+	function renderMenu(params) {
+		
+		let html="<ul>";
+		let index=0;
+		let focusIndex = params.focus%data.length;
+		for (const it of data) {
+			html +="<li ";
+			if(focusIndex==index){
+				html +="class='focus' "
+			}
+			index++;
+			html +=">"+index+ ". "+it+"<li>";
+		}
+		return html;
+	}
+	/*
+	// element:  t.refs.textarea
+function getCaretPosition(element) {
+  let left;
+  let top;
+  if (document.selection) {
+    element.focus();
+    const range = document.selection.createRange();
+    left = range.boundingLeft + element.scrollLeft;
+    top = range.boundingTop + element.scrollTop;
+  } else {
+    const SHADOWEDITOR = '__shadow_editor__';
+    const SHADOWEDITORTEXT = '__shadow_editor_text__';
+    const SHADOWEDITORCARET = '__shadow_editor_caret__';
+    const shadowEditor = element[SHADOWEDITOR] || document.createElement('div');
+    const shadowEditorCaret = element[SHADOWEDITORCARET] || document.createElement('span');
+    const shadowEditorText = element[SHADOWEDITORTEXT] || document.createElement('span');
+    let focusOffset = { left: 0, top: 0 };
+    if (!element[SHADOWEDITOR]) {
+      // add shadpw element to element's cache
+      element[SHADOWEDITOR] = shadowEditor;
+      element[SHADOWEDITORCARET] = shadowEditorCaret;
+      element[SHADOWEDITORTEXT] = shadowEditorText;
+      // append shadow to document body
+      shadowEditor.appendChild(shadowEditorText);
+      shadowEditor.appendChild(shadowEditorCaret);
+      document.body.appendChild(shadowEditor);
+      // set shadow element's style
+      const style = shadowEditor.style;
+      const computed = window.getComputedStyle ? getComputedStyle(element) : element.currentStyle;  // currentStyle for IE < 9
+
+      if (element.nodeName != 'INPUT') {
+        // only for textarea
+        style.whiteSpace = 'pre-wrap';
+        style.wordWrap = 'break-word';
+      } else {
+        style.whiteSpace = 'nowrap';
+      }
+
+      style.position = 'absolute';
+      style.overflow = 'hidden';
+      style.visibility = 'hidden';
+      properties.forEach((prop) => {
+        style[prop] = computed[prop];
+      });
+
+      shadowEditorCaret.textContent = '|';
+      shadowEditorCaret.style.cssText = 'display:inline-block;width:0;overflow:hidden;word-wrap:break-word;word-break:break-all;';
+    }
+    const offset = getElementOffset(element);
+    shadowEditor.style.top = `${offset.top}px`;
+    shadowEditor.style.left = `${offset.left}px`;
+    const index = element.selectionEnd;
+    const SHADOWEDITORCONTENT = element.value.substring(0, index);
+    shadowEditorText.textContent = SHADOWEDITORCONTENT;
+
+    shadowEditorCaret.style.display = 'inline-block';
+    try { focusOffset = getElementOffset(shadowEditorCaret); } catch (e) { }
+    shadowEditorCaret.style.display = 'none';
+    left = focusOffset.left - element.scrollLeft;
+    top = focusOffset.top - element.scrollTop;
+    const winOffset = getScrollOffset();
+    left -= winOffset.x;
+    top -= winOffset.y;
+  }
+  return {
+    left,
+    top,
+  };
+}
+	*/
+
+	/*
+如果你只是想获得输入框中光标的 offset 的话, 你可以用从 At.js 剥离出来的 jQuery 插件: Caret.js
+
+可以是用AT-JS jquery插件来实现你需要的效果:
+
+下载地址:
+
+http://pan.baidu.com/share/link?shareid=495943&uk=386708086
+
+使用方法:
+
+$("input[name=message]").atWho("@",{
+tpl: "<li id='${uid}' data-value='${name}'>${name} <small>${spacenote}</small></li>",
+'data':friend_list
+});
+评论
+但是如果你想做,你题目描述的东西的话,还是建议用插件。 这里有一个不错的jquery插件: http://ichord.github.io/At.js/
+
+评论
+
+	*/
+</script>
+
+	</body>
+</html>