s4

view s4-main.js @ 872:d0572292d033

Make blocks in table.bloghead inline-block
author HIROSE Yuuji <yuuji@gentei.org>
date Wed, 21 Oct 2020 09:27:54 +0859
parents a9e147e355fd
children 5843755e3b30
line source
1 (function (){
2 function collectElementsByAttr(elm, attr, val) {
3 var e = document.getElementsByTagName(elm);
4 if (!e) return null;
5 var list = [];
6 for (var i of e) {
7 if (i.getAttribute(attr) == val)
8 list.push(i)
9 }
10 return list;
11 }
12 function nthChildOf(parent, n, elem) { // Return Nth child of type ELEM
13 // N begins with 1
14 var i=0;
15 var le = elem.toLowerCase();
16 for (var c of parent.childNodes) {
17 if (!c.tagName) continue;
18 if (c.tagName.toLowerCase() == le) {
19 if (++i >= n) return c;
20 }
21 }
22 return null;
23 }
24 function insertRedirect(e) {
25 var articleId, textarea = document.getElementById("text");
26 var p = e.target, checked = p.checked;
27 while (p = p.parentNode)
28 if (p.nodeName.match(/^td$/i)) break;
29 if (!p) return;
30 while (p = p.nextSibling)
31 if (p.nodeName.match(/^td$/i)) break;
32 if (!p) return;
33 articleId = p.getAttribute("id");
34 if (textarea && articleId) {
35 var tv = textarea.value, lines;
36 if (tv)
37 lines = tv.split("\n");
38 else
39 lines = [""];
40 var re = new RegExp("[, ]*#"+articleId+"(?![0-9])");
41 checked = (p.nodeName.match(/^input$/)
42 ? p.checked // checkbox obeys its status
43 : !lines[0].match(re)) // a-elment toggles redirection
44 if (checked) {
45 if (!lines[0].match(re)) {
46 var re2 = new RegExp(/>#[#0-9, ]+[0-9]/);
47 if (lines[0].match(re2))
48 lines[0] = lines[0].replace(
49 re2, '$&, '+'#'+articleId);
50 else {
51 if (lines[0] > "") lines[0] = " "+lines[0];
52 lines[0] = ">#"+articleId+lines[0];
53 }
54 }
55 } else { // Remove #xxxxx
56 if (lines[0].match(/^>#[0-9 ,]+#/)) // 2 or more #id's
57 lines[0] = lines[0].replace(
58 new RegExp("^>#"+articleId+"[ ,]*"), ">").replace(
59 new RegExp("[ ,]*#"+articleId), "");
60 else {
61 lines[0] = lines[0].replace(
62 new RegExp(">#"+articleId+"[ ,]*"), "");
63 }
64 }
65 lines[0] = lines[0].replace(/^> *$/, '');
66 textarea.value = lines.join("\n");
67 }
68 }
69 function reverseChecks() {
70 var names = collectElementsByAttr("input", "name", "usel");
71 for (let u of names) {
72 u.checked = !u.checked;
73 }
74 }
75 function renumberOL(str, start) {
76 var stra = str.split("\n");
78 for (var i=1; i<stra.length; i++) {
79 if (stra[i].match(/^[1-9][0-9]*\. /)) {
80 let orig=stra[i];
81 stra[i] = (++start)+". "+RegExp.rightContext;
82 } else if (stra[i].match(/^ /)) {
83 continue;
84 } else
85 break;
86 }
87 return stra.join("\n");
88 }
89 function submitThisForm(input) {
90 for (var elm=input.parentNode; elm; elm = elm.parentNode) {
91 if (elm.nodeName.match(/form/i)) {
92 elm.submit();
93 return true;
94 }
95 }
96 return false;
97 }
98 function helpMarkdownBS(e) {
99 var area = e.target, pos = area.selectionStart, text = area.value;
100 if (area.selectionStart != area.selectionEnd) return;
101 if (pos<2) return;
102 if (text.substr(pos-1, 2)=="\n\n") return;
103 var bol = text.lastIndexOf("\n", pos-1),
104 eol = text.indexOf("\n", pos);
105 if (bol<=0 || bol==eol) return;
106 var thisline = text.substring(bol+1, eol==-1 ? text.length : eol);
107 thisline = text.substring(bol+1, pos);
108 if (thisline == "* ") {
109 area.setSelectionRange(pos-2, pos);
110 } else if (thisline.match(/^[1-9][0-9]*\. $/)) {
111 area.setSelectionRange(pos-RegExp.lastMatch.length, pos);
112 }
113 }
114 function helpMarkdownEnter(e) {
115 if (e.keyCode == 13 && !e.shiftKey) {
116 if (e.metaKey && submitThisForm(e.target)) {
117 e.preventDefault();
118 return;
119 }
120 var area = e.target;
121 var pos = area.selectionStart, text = area.value;
122 if (pos==0) return;
123 var last = text.lastIndexOf("\n", pos-1);
124 var rest = text.substring(pos), rest0=rest;
125 var line = last ? text.substring(last+1, pos) : text;
126 var next = rest.substring(rest.indexOf("\n"))||rest;
127 next=next.substring(1);
128 var tail = text.substring(pos-2, pos), br = (tail==" ");
129 var add = "", offset = 1;
130 if (line.startsWith("* ")) {
131 add = "* ";
132 offset += add.length;
133 if (br) {
134 add = " " + "\n" + add;
135 }
136 } else if (line.match(/^([1-9][0-9]*)\. /)) {
137 var ln = parseInt(RegExp.$1), nn=ln+1,
138 len = RegExp.lastMatch.length;
139 add = nn+". ";
140 let toeol = text.substr(pos, text.indexOf("\n"));
141 if (br) {
142 if (next.startsWith(add)) {
143 add=" ".repeat(len);
144 nn = ln;
145 } else {
146 add = " ".repeat(len)+ "\n" + add;
147 offset -= len+1;
148 }
149 }
150 if (next.match(/^[1-9][0-9]*\. /))
151 rest = renumberOL(rest, nn);
152 offset += add.length;
153 } else if (line.match(/^\|( *).+\|/)) {
154 add = "|" + RegExp.$1 + " |";
155 offset += add.length-2;
156 } else {
157 return;
158 }
159 e.preventDefault();
160 if (!document.execCommand("insertText", false, "\n"+add)) {
161 //Firefox
162 area.selectionEnd = area.value.length;
163 area.setRangeText("\n"+add+rest);
164 area.selectionEnd = null;
165 } else {
166 area.selectionEnd = area.value.length;
167 area.setSelectionRange(area.selectionStart, area.value.length);
168 document.execCommand("insertText", false, rest);
169 area.selectionEnd = null;
170 area.focus();
171 }
172 area.selectionStart = pos+offset;
173 return;
174 if (document.execCommand("insertText", false, "\n"+add)) {
175 //area.setSelectionRange(area.selectionStart, text.length);
176 // alert("rest=["+rest+"], add=["+add+"]");
177 alert(text.substring(pos, area.value.length));
178 if (rest != rest0) {
179 area.setSelectionRange(pos, area.value.length);
180 return;
181 document.execCommand("delete");
182 }
183 document.execCommand("insertText", false, rest);
184 } else {
185 // Firefox cannot use insertText in textarea...
186 area.value = text.substring(0, pos) + "\n" + add + rest;
187 }
188 //area.setSelectionRange(pos+length(add));
189 area.selectionStart=area.selectionEnd = (pos + offset);
191 }
192 }
193 function helpMarkdown(e) {
194 switch (e.keyCode) {
195 case 8: helpMarkdownBS(e); break;
196 case 13: helpMarkdownEnter(e); break;
197 }
198 }
199 /* Init event listeners */
200 function addFileInput() {
201 var inpfile = collectElementsByAttr("input", "name", "image");
202 if (!inpfile) return;
203 var filled = true;
204 var i, ih;
205 for (i of inpfile) {
206 if (! i.value) filled=false;
207 }
208 if (filled) {
209 ih = i.parentNode.innerHTML;
210 if (ih) {
211 var inpf = ih.substring(ih.indexOf("<input")),
212 newi = "<br>"+inpf.substring(0, inpf.indexOf(">")+1);
213 i.insertAdjacentHTML("afterend", newi)
214 // alert(newi);
215 }
216 }
217 }
218 function initFileInput() { // Multiplies "input type=file"
219 var el, morefile = document.getElementById("morefile");
220 if (morefile) {
221 for (el of collectElementsByAttr("input", "name", "image")) {
222 el.addEventListener("change", function(ev) {
223 if (ev.target.value > "" && ev.target.files.length == 1)
224 morefile.style.visibility = "visible";
225 // No need to hide again, sure?
226 });
227 }
228 morefile.addEventListener("click", addFileInput, null);
229 }
230 // When renaming, select basename part
231 for (el of collectElementsByAttr("input", "class", "mv")) {
232 el.addEventListener("focus", function(ev) {
233 var i = ev.target;
234 if (i) {
235 i.setSelectionRange(0, i.value.lastIndexOf("."));
236 }
237 });
238 }
239 }
240 function initTextarea() {
241 var te = collectElementsByAttr("textarea", "name", "text");
242 if (!te || !te[0]) return;
243 te[0].addEventListener("keydown", helpMarkdown, false);
244 }
245 function initBlogs() {
246 // Auto-complete #xxxx
247 var check = collectElementsByAttr("input", "name", "notifyto");
248 if (check)
249 for (let i of check) {
250 i.addEventListener("click", insertRedirect, null);
251 }
252 for (let i of document.getElementsByTagName("a"))
253 if (i.getAttribute("href").match(/^#[0-9]+$/))
254 if (RegExp.lastMatch == i.innerHTML)
255 i.addEventListener("click", insertRedirect, null)
256 }
257 function initGrpAction() {
258 var rev = document.getElementById("reverse");
259 if (!rev) return; // Is not grpAction page
260 if (rev.tagName.match(/span/i)) {
261 rev.textContent = " 反転 ";
262 rev.addEventListener("click", reverseChecks, null);
263 }
264 var emailbtn = document.getElementById("email");
265 emailbtn.addEventListener("click", function(ev){
266 // Enlarge box and Select user's checkbox
267 if (!ev.target.checked) return;
268 var x = collectElementsByAttr("div", "class", "foldtabs");
269 if (x && x[0] && x[0].style) {
270 x[0].style.height = "10em";
271 }
272 let myuid = document.getElementById("myuid");
273 if (myuid) {
274 let usel = collectElementsByAttr("input", "name", "usel");
275 if (usel) {
276 for (u of usel) {
277 if (u.value == myuid.value)
278 u.checked = true;
279 }
280 }
281 }
282 }, null);
283 var teamsel = document.getElementById("selteam");
284 if (teamsel) {
285 var usel, p, team;
286 // Select all members of the team
287 teamsel.addEventListener("change", function(ev) {
288 var teamname = teamsel.value,
289 selected = new RegExp('(^| )'+teamname+"($|,)");
290 usel = collectElementsByAttr("input", "name", "usel");
291 if (!usel) return;
292 for (u of usel) {
293 p = u.parentNode; // should be label
294 if (!p) continue;
295 if (teamname == "TEAM") { // Reset all checks
296 u.checked = false; // when "TEAM" is selected
297 } else {
298 p = p.parentNode.parentNode;// should be tr
299 team = nthChildOf(p, 3, "td")
300 if (team && team.textContent
301 && team.textContent.match(selected)) {
302 u.checked = true;
303 }
304 }
305 }
306 }, null);
307 }
308 }
309 function init() {
310 initGrpAction();
311 initBlogs();
312 initFileInput();
313 initTextarea();
314 }
315 document.addEventListener('DOMContentLoaded', init, null);
316 })();