changeset 1040:78e904f9be34 draft

Add Filtering by TEAM
author HIROSE Yuuji <yuuji@gentei.org>
date Sun, 21 Apr 2024 11:30:46 +0900
parents 68a01c699acb
children 8682149ed229
files examples/common/default/default.css s4-blog.sh s4-funcs.sh s4-main.js
diffstat 4 files changed, 108 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/examples/common/default/default.css	Sat Apr 06 18:08:10 2024 +0900
+++ b/examples/common/default/default.css	Sun Apr 21 11:30:46 2024 +0900
@@ -177,9 +177,12 @@
     display: inline-block; border-radius: 0.8ex;
 }
 td.repl.atall:first-line {font-size: 125%;}
+p.filter {	/* is located after .blog_replies */
+    margin: 0; padding: 0 1ex;
+}
 
 .blog_replies td.repatt {min-width: 12em;}
-.blog_replies td.hideauthor {display: none;}
+.blog_replies td.hideauthor, .hide {display: none;}
 table.blog_replies iframe {
     width: 80%; min-height: 300px; max-width: 50em; max-height: 80vw;
     padding: 0; border: 0;
--- a/s4-blog.sh	Sat Apr 06 18:08:10 2024 +0900
+++ b/s4-blog.sh	Sun Apr 21 11:30:46 2024 +0900
@@ -164,7 +164,12 @@
   # blog_m: *article
 
   blogowner=`getvalbyid blog owner "$2"`
-  isgroup "$blogowner" && isgroup=true || isgroup=false
+  if isgroup "$blogowner"; then
+    isgroup=true; qgrp=`sqlquote "$blogowner"`
+  else
+    isgroup=false
+  fi
+	
   isgrpadmin=false
   isgrpowner "$user" "$blogowner" && isgrpadmin=true
   [ x"$user" = x"$blogowner" ] && isgrpadmin=true
@@ -197,7 +202,6 @@
     *quiz*|*close*|"")	# When blog_mode is "", fallback to quiz/close
       f_exclusive=1
       if $isgroup; then
-	qgrp=`sqlquote "$blogowner"`
 	if $isgrpadmin; then
 	  F_UNREADABLE="''"
 	else
@@ -278,7 +282,7 @@
   hidebtn='<button type="button" id="hideauth" accesskey="a" title="Shortcut: A
 Hide/Show Author - Useful for summary printing
 OFFにするとまとめ印刷に便利。">著者OFF</button>'
-  href4="${blog_math:+<span id=\"mathjax\">Math</span>} $hidebtn <a href=\"#bottom\" accesskey=\"b\" title=\"Shortcut: B${nl}to the Bottom\"> 末尾へ</a>"
+  href4="${blog_math:+<span id=\"mathjax\">Math</span>} $hidebtn <a href=\"#bottom\" accesskey=\"b\" id=\"tailbtn\" title=\"Shortcut: B${nl}to the Bottom\"> 末尾へ</a>"
   $isgrpadmin &&
       href5="<a href=\"?blogseen+$rowid\" accesskey=\"s\" title=\"Shortcut: S${nl}State of Accesses\"> 読刻</a>"
   quizmodefile=$tmpd/quiz; rm -f "$quizmodefile"	# XXX: Global state
@@ -445,7 +449,7 @@
     #CAT="tail -n $nlimit"
     CAT=cat
     limitedmsg="<span class=\"warn\">※最新${nlimit}件のみの表示※</span>"
-    showalllink="<a title=\"Show All\" href=\"?replyblog+$rowid+n:all\">全件表示</a>"
+    showalllink="<a id=\"showall\" title=\"Show All\" href=\"?replyblog+$rowid+n:all\">全件表示</a>"
     cat<<-EOF > $omitline
 	<tr class="warn">
 	<th>:<br>$limitedmsg<br>($((narts-$nlimit-1))件省略)<br>:</th>
@@ -649,6 +653,19 @@
 	  title="Shortcut: T${nl}to the Top">先頭へ</a>
 	 ${showalllink:+/ `echo $showalllink|sed 's/n:all/&\#bottom/'`$limitedmsg}</p>
 	EOF
+  # Put team list
+  if $usejson && $isgrp; then
+    echo '<table id="team4filter" style="display: none;">'
+    query<<-EOF
+	.mode html
+	SELECT val, json_group_array(b.rowid) mems
+	FROM grp_mem_m a LEFT JOIN user b ON a.user=b.name
+	WHERE gname = $qgrp AND key='team'
+	GROUP BY val;
+	.mode list
+	EOF
+    echo '</table>'
+  fi
   $iswritable && cat<<-EOF
 	<div class="blogcomment">
 	<input type="hidden" name="blogid" value="$id">
--- a/s4-funcs.sh	Sat Apr 06 18:08:10 2024 +0900
+++ b/s4-funcs.sh	Sun Apr 21 11:30:46 2024 +0900
@@ -93,6 +93,7 @@
 likeesc=`printf '\037'`		# ESCAPE char of LIKE operator
 iconcachekey="profimgcache_S"
 asdelim=":::"			# delimiter of dumptable td-class specifier
+sqlite3 --help 2>&1 | grep -q -- '-json' && usejson=true || usejson=false
 
 # Start debug logging
 logtag="($$)${S4WORLD:+{$S4WORLD\}}"
--- a/s4-main.js	Sat Apr 06 18:08:10 2024 +0900
+++ b/s4-main.js	Sun Apr 21 11:30:46 2024 +0900
@@ -8,6 +8,7 @@
 	mypath = myurl.substring(myurl.lastIndexOf("/"));
     var art_m_list = [];
     var mathjax = false;
+    var filterSelect, filterOption = null;
     let input_pdfsw = 'input[name="comppdf"]';
     if (mypath.match(/(.*)\/(.*)/)) {
 	mypath = RegExp.$2;
@@ -304,6 +305,9 @@
 	    newform = new FormData(form);
 	    if (data.get("text") > "") {	// Called by submit button
 		myform.reset();
+		if (filterOption) { 		// Restore TEAM filterin if any
+		    filterSelect.selectedIndex = filterOption;
+		}
 		let pdfsw = myform.querySelector(input_pdfsw);
 		if (pdfsw) pdfsw.remove();
 		// myform.text.value = '';
@@ -839,16 +843,14 @@
 	let needBOM = e.ctrlKey;
 	if (!blogtbl) return;
 	let trw = blogtbl.querySelector("tr.warn"), a;
-	if (trw && (a=trw.querySelector("th>a"))) {
-	    if (a.title == "Show All") {
-		if (window.confirm(`50件以下に表示制限されています。
+	if (trw && (a=document.getElementById("showall"))) {
+	    if (window.confirm(`50件以下に表示制限されています。
 取得し直しますか?
 Cancelを押すとこのまま取得します。
 Seen articles limited to 50 items.
 Push OK to get all articles, Cancel to get only seen articles.`)) {
-		    a.click();
-		    return;
-		}
+		a.click();
+		return;
 	    }
 	}
 	if (navigator.userAgent.match(/Windows/)) {
@@ -964,8 +966,8 @@
 	atMarkView(document);
 	/*****************************************************************/
 	//(2) Prepare sort
-	let warn = document.querySelector("tr.warn span.warn");
-	if (blogheadtd && warn==null) {
+	let limit50 = document.getElementById("showall");
+	if (blogheadtd && limit50==null) {
 	    let umode = "byUser", amode = "byArticle";
 	    let sbtn = document.createElement("button");
 	    sbtn.textContent = umode;
@@ -1018,6 +1020,78 @@
 		sbtn.textContent = uidsort ? amode : umode;
 	    });
 	}
+	/*****************************************************************/
+	//(3) Prepare Filtering by Team
+	let teamfilter = document.getElementById("team4filter");
+	if (blogheadtd && teamfilter) {
+	    let teams = {};
+	    for (let row of teamfilter.querySelectorAll("tr")) {
+		let cols = row.querySelectorAll("td");
+		if (cols.length == 2) {
+		    // <TD>TeamName</TD><TD>["user1@dom1","user2@dom2"]</td>
+		    teams[cols[0].textContent] = cols[1].textContent;
+		}
+	    }
+	    if (Object.keys(teams).length > 0) {
+		function filterArticles(e) {
+		    if (limit50) {
+			if (window.confirm(`表示数制限があります。
+全件表示に切り替えますか。Cencel すると限定表示のまま絞り込みます。
+Not all articles are seen.
+Push OK to switch to all-articles mode, Cencel to continue without limit.`)) {
+			    limit50.click();
+			    return;
+			}
+		    }
+		    let userlist;
+		    try {
+			userlist = JSON.parse(e.target.value);
+		    } catch (e) {
+			return;
+		    }
+		    let showall = (userlist == "");
+		    let tbl = document.querySelector("table.blog_replies");
+		    for (let row of tbl.querySelectorAll("tr")) {
+			let author = row.querySelector("a[title]");
+			let visible = true;
+			if (!showall && author) {
+			    let home = author.href;
+			    if (home && home.match(/home\+([0-9]+)/)) {
+				let uid = RegExp.$1;
+				visible = userlist.find(e=>e==uid)
+			    }
+			}
+			if (visible)
+			    row.classList.remove("hide")
+			else
+			    row.classList.add("hide")
+			filterOption = e.target.selectedIndex;
+		    }
+		    
+		}
+		// Do Filter Addition
+		let optall = document.createElement("option");
+		filterSelect = document.createElement("select");
+		optall.textContent = "-- ALL(全件) --";
+		optall.value = '""';		// -> showall=true
+		filterSelect.appendChild(optall);
+		filterSelect.addEventListener('change', filterArticles, false)
+		for (let k in teams) {
+		    let o = document.createElement("option");
+		    o.textContent = k;
+		    o.value = teams[k];
+		    filterSelect.appendChild(o);
+		}
+		let table = document.querySelector("table.blog_replies");
+		if (table) {
+		    let p = document.createElement("p");
+		    p.textContent = "Filter by TEAM: ";
+		    p.classList.add("filter");
+		    p.appendChild(filterSelect);
+		    table.insertAdjacentElement('beforebegin', p)
+		}
+	    }
+	}
     }
     function initGrpAction() {
 	var rev = document.getElementById("reverse");

yatex.org