rev |
line source |
yuuji@889
|
1 // 愛
|
yuuji@586
|
2 (function (){
|
yuuji@667
|
3 function collectElementsByAttr(elm, attr, val) {
|
yuuji@586
|
4 var e = document.getElementsByTagName(elm);
|
yuuji@586
|
5 if (!e) return null;
|
yuuji@586
|
6 var list = [];
|
yuuji@586
|
7 for (var i of e) {
|
yuuji@667
|
8 if (i.getAttribute(attr) == val)
|
yuuji@586
|
9 list.push(i)
|
yuuji@586
|
10 }
|
yuuji@586
|
11 return list;
|
yuuji@586
|
12 }
|
yuuji@675
|
13 function nthChildOf(parent, n, elem) { // Return Nth child of type ELEM
|
yuuji@675
|
14 // N begins with 1
|
yuuji@675
|
15 var i=0;
|
yuuji@675
|
16 var le = elem.toLowerCase();
|
yuuji@675
|
17 for (var c of parent.childNodes) {
|
yuuji@675
|
18 if (!c.tagName) continue;
|
yuuji@675
|
19 if (c.tagName.toLowerCase() == le) {
|
yuuji@675
|
20 if (++i >= n) return c;
|
yuuji@675
|
21 }
|
yuuji@675
|
22 }
|
yuuji@675
|
23 return null;
|
yuuji@675
|
24 }
|
yuuji@586
|
25 function insertRedirect(e) {
|
yuuji@586
|
26 var articleId, textarea = document.getElementById("text");
|
yuuji@586
|
27 var p = e.target, checked = p.checked;
|
yuuji@586
|
28 while (p = p.parentNode)
|
yuuji@586
|
29 if (p.nodeName.match(/^td$/i)) break;
|
yuuji@586
|
30 if (!p) return;
|
yuuji@586
|
31 while (p = p.nextSibling)
|
yuuji@586
|
32 if (p.nodeName.match(/^td$/i)) break;
|
yuuji@586
|
33 if (!p) return;
|
yuuji@586
|
34 articleId = p.getAttribute("id");
|
yuuji@586
|
35 if (textarea && articleId) {
|
yuuji@586
|
36 var tv = textarea.value, lines;
|
yuuji@586
|
37 if (tv)
|
yuuji@586
|
38 lines = tv.split("\n");
|
yuuji@586
|
39 else
|
yuuji@586
|
40 lines = [""];
|
yuuji@586
|
41 var re = new RegExp("[, ]*#"+articleId+"(?![0-9])");
|
yuuji@590
|
42 checked = (p.nodeName.match(/^input$/)
|
yuuji@590
|
43 ? p.checked // checkbox obeys its status
|
yuuji@590
|
44 : !lines[0].match(re)) // a-elment toggles redirection
|
yuuji@586
|
45 if (checked) {
|
yuuji@586
|
46 if (!lines[0].match(re)) {
|
yuuji@586
|
47 var re2 = new RegExp(/>#[#0-9, ]+[0-9]/);
|
yuuji@586
|
48 if (lines[0].match(re2))
|
yuuji@586
|
49 lines[0] = lines[0].replace(
|
yuuji@586
|
50 re2, '$&, '+'#'+articleId);
|
yuuji@586
|
51 else {
|
yuuji@586
|
52 if (lines[0] > "") lines[0] = " "+lines[0];
|
yuuji@586
|
53 lines[0] = ">#"+articleId+lines[0];
|
yuuji@586
|
54 }
|
yuuji@586
|
55 }
|
yuuji@586
|
56 } else { // Remove #xxxxx
|
yuuji@586
|
57 if (lines[0].match(/^>#[0-9 ,]+#/)) // 2 or more #id's
|
yuuji@586
|
58 lines[0] = lines[0].replace(
|
yuuji@586
|
59 new RegExp("^>#"+articleId+"[ ,]*"), ">").replace(
|
yuuji@586
|
60 new RegExp("[ ,]*#"+articleId), "");
|
yuuji@586
|
61 else {
|
yuuji@586
|
62 lines[0] = lines[0].replace(
|
yuuji@586
|
63 new RegExp(">#"+articleId+"[ ,]*"), "");
|
yuuji@586
|
64 }
|
yuuji@586
|
65 }
|
yuuji@586
|
66 lines[0] = lines[0].replace(/^> *$/, '');
|
yuuji@586
|
67 textarea.value = lines.join("\n");
|
yuuji@586
|
68 }
|
yuuji@586
|
69 }
|
yuuji@659
|
70 function reverseChecks() {
|
yuuji@667
|
71 var names = collectElementsByAttr("input", "name", "usel");
|
yuuji@659
|
72 for (let u of names) {
|
yuuji@659
|
73 u.checked = !u.checked;
|
yuuji@659
|
74 }
|
yuuji@659
|
75 }
|
yuuji@852
|
76 function renumberOL(str, start) {
|
yuuji@852
|
77 var stra = str.split("\n");
|
yuuji@852
|
78
|
yuuji@852
|
79 for (var i=1; i<stra.length; i++) {
|
yuuji@852
|
80 if (stra[i].match(/^[1-9][0-9]*\. /)) {
|
yuuji@852
|
81 let orig=stra[i];
|
yuuji@852
|
82 stra[i] = (++start)+". "+RegExp.rightContext;
|
yuuji@852
|
83 } else if (stra[i].match(/^ /)) {
|
yuuji@852
|
84 continue;
|
yuuji@852
|
85 } else
|
yuuji@852
|
86 break;
|
yuuji@852
|
87 }
|
yuuji@852
|
88 return stra.join("\n");
|
yuuji@852
|
89 }
|
yuuji@852
|
90 function submitThisForm(input) {
|
yuuji@852
|
91 for (var elm=input.parentNode; elm; elm = elm.parentNode) {
|
yuuji@852
|
92 if (elm.nodeName.match(/form/i)) {
|
yuuji@852
|
93 elm.submit();
|
yuuji@852
|
94 return true;
|
yuuji@852
|
95 }
|
yuuji@852
|
96 }
|
yuuji@852
|
97 return false;
|
yuuji@852
|
98 }
|
yuuji@852
|
99 function helpMarkdownBS(e) {
|
yuuji@852
|
100 var area = e.target, pos = area.selectionStart, text = area.value;
|
yuuji@852
|
101 if (area.selectionStart != area.selectionEnd) return;
|
yuuji@852
|
102 if (pos<2) return;
|
yuuji@852
|
103 if (text.substr(pos-1, 2)=="\n\n") return;
|
yuuji@852
|
104 var bol = text.lastIndexOf("\n", pos-1),
|
yuuji@852
|
105 eol = text.indexOf("\n", pos);
|
yuuji@852
|
106 if (bol<=0 || bol==eol) return;
|
yuuji@852
|
107 var thisline = text.substring(bol+1, eol==-1 ? text.length : eol);
|
yuuji@852
|
108 thisline = text.substring(bol+1, pos);
|
yuuji@852
|
109 if (thisline == "* ") {
|
yuuji@852
|
110 area.setSelectionRange(pos-2, pos);
|
yuuji@852
|
111 } else if (thisline.match(/^[1-9][0-9]*\. $/)) {
|
yuuji@852
|
112 area.setSelectionRange(pos-RegExp.lastMatch.length, pos);
|
yuuji@852
|
113 }
|
yuuji@852
|
114 }
|
yuuji@852
|
115 function helpMarkdownEnter(e) {
|
yuuji@852
|
116 if (e.keyCode == 13 && !e.shiftKey) {
|
yuuji@852
|
117 if (e.metaKey && submitThisForm(e.target)) {
|
yuuji@852
|
118 e.preventDefault();
|
yuuji@852
|
119 return;
|
yuuji@852
|
120 }
|
yuuji@846
|
121 var area = e.target;
|
yuuji@846
|
122 var pos = area.selectionStart, text = area.value;
|
yuuji@847
|
123 if (pos==0) return;
|
yuuji@846
|
124 var last = text.lastIndexOf("\n", pos-1);
|
yuuji@852
|
125 var rest = text.substring(pos), rest0=rest;
|
yuuji@852
|
126 var line = last ? text.substring(last+1, pos) : text;
|
yuuji@852
|
127 var next = rest.substring(rest.indexOf("\n"))||rest;
|
yuuji@852
|
128 next=next.substring(1);
|
yuuji@847
|
129 var tail = text.substring(pos-2, pos), br = (tail==" ");
|
yuuji@847
|
130 var add = "", offset = 1;
|
yuuji@846
|
131 if (line.startsWith("* ")) {
|
yuuji@847
|
132 add = "* ";
|
yuuji@847
|
133 offset += add.length;
|
yuuji@847
|
134 if (br) {
|
yuuji@847
|
135 add = " " + "\n" + add;
|
yuuji@847
|
136 }
|
yuuji@846
|
137 } else if (line.match(/^([1-9][0-9]*)\. /)) {
|
yuuji@852
|
138 var ln = parseInt(RegExp.$1), nn=ln+1,
|
yuuji@852
|
139 len = RegExp.lastMatch.length;
|
yuuji@852
|
140 add = nn+". ";
|
yuuji@852
|
141 let toeol = text.substr(pos, text.indexOf("\n"));
|
yuuji@852
|
142 if (br) {
|
yuuji@852
|
143 if (next.startsWith(add)) {
|
yuuji@852
|
144 add=" ".repeat(len);
|
yuuji@852
|
145 nn = ln;
|
yuuji@852
|
146 } else {
|
yuuji@852
|
147 add = " ".repeat(len)+ "\n" + add;
|
yuuji@852
|
148 offset -= len+1;
|
yuuji@852
|
149 }
|
yuuji@852
|
150 }
|
yuuji@852
|
151 if (next.match(/^[1-9][0-9]*\. /))
|
yuuji@852
|
152 rest = renumberOL(rest, nn);
|
yuuji@847
|
153 offset += add.length;
|
yuuji@852
|
154 } else if (line.match(/^\|( *).+\|/)) {
|
yuuji@846
|
155 add = "|" + RegExp.$1 + " |";
|
yuuji@847
|
156 offset += add.length-2;
|
yuuji@847
|
157 } else {
|
yuuji@847
|
158 return;
|
yuuji@846
|
159 }
|
yuuji@847
|
160 e.preventDefault();
|
yuuji@852
|
161 if (!document.execCommand("insertText", false, "\n"+add)) {
|
yuuji@852
|
162 //Firefox
|
yuuji@852
|
163 area.selectionEnd = area.value.length;
|
yuuji@852
|
164 area.setRangeText("\n"+add+rest);
|
yuuji@852
|
165 area.selectionEnd = null;
|
yuuji@852
|
166 } else {
|
yuuji@852
|
167 area.selectionEnd = area.value.length;
|
yuuji@852
|
168 area.setSelectionRange(area.selectionStart, area.value.length);
|
yuuji@852
|
169 document.execCommand("insertText", false, rest);
|
yuuji@852
|
170 area.selectionEnd = null;
|
yuuji@852
|
171 area.focus();
|
yuuji@852
|
172 }
|
yuuji@852
|
173 area.selectionStart = pos+offset;
|
yuuji@852
|
174 return;
|
yuuji@852
|
175 if (document.execCommand("insertText", false, "\n"+add)) {
|
yuuji@852
|
176 //area.setSelectionRange(area.selectionStart, text.length);
|
yuuji@852
|
177 // alert("rest=["+rest+"], add=["+add+"]");
|
yuuji@852
|
178 alert(text.substring(pos, area.value.length));
|
yuuji@852
|
179 if (rest != rest0) {
|
yuuji@852
|
180 area.setSelectionRange(pos, area.value.length);
|
yuuji@852
|
181 return;
|
yuuji@852
|
182 document.execCommand("delete");
|
yuuji@852
|
183 }
|
yuuji@852
|
184 document.execCommand("insertText", false, rest);
|
yuuji@852
|
185 } else {
|
yuuji@852
|
186 // Firefox cannot use insertText in textarea...
|
yuuji@852
|
187 area.value = text.substring(0, pos) + "\n" + add + rest;
|
yuuji@852
|
188 }
|
yuuji@846
|
189 //area.setSelectionRange(pos+length(add));
|
yuuji@847
|
190 area.selectionStart=area.selectionEnd = (pos + offset);
|
yuuji@847
|
191
|
yuuji@846
|
192 }
|
yuuji@846
|
193 }
|
yuuji@852
|
194 function helpMarkdown(e) {
|
yuuji@852
|
195 switch (e.keyCode) {
|
yuuji@852
|
196 case 8: helpMarkdownBS(e); break;
|
yuuji@852
|
197 case 13: helpMarkdownEnter(e); break;
|
yuuji@852
|
198 }
|
yuuji@852
|
199 }
|
yuuji@846
|
200 /* Init event listeners */
|
yuuji@837
|
201 function addFileInput() {
|
yuuji@837
|
202 var inpfile = collectElementsByAttr("input", "name", "image");
|
yuuji@837
|
203 if (!inpfile) return;
|
yuuji@837
|
204 var filled = true;
|
yuuji@837
|
205 var i, ih;
|
yuuji@837
|
206 for (i of inpfile) {
|
yuuji@837
|
207 if (! i.value) filled=false;
|
yuuji@837
|
208 }
|
yuuji@837
|
209 if (filled) {
|
yuuji@837
|
210 ih = i.parentNode.innerHTML;
|
yuuji@837
|
211 if (ih) {
|
yuuji@837
|
212 var inpf = ih.substring(ih.indexOf("<input")),
|
yuuji@837
|
213 newi = "<br>"+inpf.substring(0, inpf.indexOf(">")+1);
|
yuuji@837
|
214 i.insertAdjacentHTML("afterend", newi)
|
yuuji@837
|
215 // alert(newi);
|
yuuji@837
|
216 }
|
yuuji@837
|
217 }
|
yuuji@837
|
218 }
|
yuuji@837
|
219 function initFileInput() { // Multiplies "input type=file"
|
yuuji@837
|
220 var el, morefile = document.getElementById("morefile");
|
yuuji@837
|
221 if (morefile) {
|
yuuji@837
|
222 for (el of collectElementsByAttr("input", "name", "image")) {
|
yuuji@837
|
223 el.addEventListener("change", function(ev) {
|
yuuji@837
|
224 if (ev.target.value > "" && ev.target.files.length == 1)
|
yuuji@837
|
225 morefile.style.visibility = "visible";
|
yuuji@837
|
226 // No need to hide again, sure?
|
yuuji@837
|
227 });
|
yuuji@837
|
228 }
|
yuuji@837
|
229 morefile.addEventListener("click", addFileInput, null);
|
yuuji@837
|
230 }
|
yuuji@837
|
231 // When renaming, select basename part
|
yuuji@837
|
232 for (el of collectElementsByAttr("input", "class", "mv")) {
|
yuuji@837
|
233 el.addEventListener("focus", function(ev) {
|
yuuji@837
|
234 var i = ev.target;
|
yuuji@837
|
235 if (i) {
|
yuuji@837
|
236 i.setSelectionRange(0, i.value.lastIndexOf("."));
|
yuuji@837
|
237 }
|
yuuji@837
|
238 });
|
yuuji@837
|
239 }
|
yuuji@837
|
240 }
|
yuuji@846
|
241 function initTextarea() {
|
yuuji@846
|
242 var te = collectElementsByAttr("textarea", "name", "text");
|
yuuji@846
|
243 if (!te || !te[0]) return;
|
yuuji@846
|
244 te[0].addEventListener("keydown", helpMarkdown, false);
|
yuuji@846
|
245 }
|
yuuji@659
|
246 function initBlogs() {
|
yuuji@837
|
247 // Auto-complete #xxxx
|
yuuji@837
|
248 var check = collectElementsByAttr("input", "name", "notifyto");
|
yuuji@586
|
249 if (check)
|
yuuji@590
|
250 for (let i of check) {
|
yuuji@586
|
251 i.addEventListener("click", insertRedirect, null);
|
yuuji@586
|
252 }
|
yuuji@590
|
253 for (let i of document.getElementsByTagName("a"))
|
yuuji@590
|
254 if (i.getAttribute("href").match(/^#[0-9]+$/))
|
yuuji@590
|
255 if (RegExp.lastMatch == i.innerHTML)
|
yuuji@590
|
256 i.addEventListener("click", insertRedirect, null)
|
yuuji@586
|
257 }
|
yuuji@659
|
258 function initGrpAction() {
|
yuuji@659
|
259 var rev = document.getElementById("reverse");
|
yuuji@667
|
260 if (!rev) return; // Is not grpAction page
|
yuuji@667
|
261 if (rev.tagName.match(/span/i)) {
|
yuuji@659
|
262 rev.textContent = " 反転 ";
|
yuuji@659
|
263 rev.addEventListener("click", reverseChecks, null);
|
yuuji@659
|
264 }
|
yuuji@667
|
265 var emailbtn = document.getElementById("email");
|
yuuji@667
|
266 emailbtn.addEventListener("click", function(ev){
|
yuuji@675
|
267 // Enlarge box and Select user's checkbox
|
yuuji@667
|
268 if (!ev.target.checked) return;
|
yuuji@673
|
269 var x = collectElementsByAttr("div", "class", "foldtabs");
|
yuuji@673
|
270 if (x && x[0] && x[0].style) {
|
yuuji@673
|
271 x[0].style.height = "10em";
|
yuuji@673
|
272 }
|
yuuji@667
|
273 let myuid = document.getElementById("myuid");
|
yuuji@667
|
274 if (myuid) {
|
yuuji@667
|
275 let usel = collectElementsByAttr("input", "name", "usel");
|
yuuji@667
|
276 if (usel) {
|
yuuji@667
|
277 for (u of usel) {
|
yuuji@667
|
278 if (u.value == myuid.value)
|
yuuji@667
|
279 u.checked = true;
|
yuuji@667
|
280 }
|
yuuji@667
|
281 }
|
yuuji@667
|
282 }
|
yuuji@667
|
283 }, null);
|
yuuji@675
|
284 var teamsel = document.getElementById("selteam");
|
yuuji@675
|
285 if (teamsel) {
|
yuuji@675
|
286 var usel, p, team;
|
yuuji@675
|
287 // Select all members of the team
|
yuuji@675
|
288 teamsel.addEventListener("change", function(ev) {
|
yuuji@675
|
289 var teamname = teamsel.value,
|
yuuji@676
|
290 selected = new RegExp('(^| )'+teamname+"($|,)");
|
yuuji@675
|
291 usel = collectElementsByAttr("input", "name", "usel");
|
yuuji@675
|
292 if (!usel) return;
|
yuuji@675
|
293 for (u of usel) {
|
yuuji@675
|
294 p = u.parentNode; // should be label
|
yuuji@675
|
295 if (!p) continue;
|
yuuji@675
|
296 if (teamname == "TEAM") { // Reset all checks
|
yuuji@675
|
297 u.checked = false; // when "TEAM" is selected
|
yuuji@675
|
298 } else {
|
yuuji@675
|
299 p = p.parentNode.parentNode;// should be tr
|
yuuji@675
|
300 team = nthChildOf(p, 3, "td")
|
yuuji@675
|
301 if (team && team.textContent
|
yuuji@675
|
302 && team.textContent.match(selected)) {
|
yuuji@675
|
303 u.checked = true;
|
yuuji@675
|
304 }
|
yuuji@675
|
305 }
|
yuuji@675
|
306 }
|
yuuji@675
|
307 }, null);
|
yuuji@675
|
308 }
|
yuuji@659
|
309 }
|
yuuji@893
|
310 function dispInfoMomentary(msg, elem) {
|
yuuji@893
|
311 // Momentarily display MSG in tooltip-baloon relative to ELEM element.
|
yuuji@893
|
312 let help = document.createElement("p");
|
yuuji@893
|
313 elem.style.position = 'relative';
|
yuuji@893
|
314 elem.style.overflow = 'visible';
|
yuuji@893
|
315 help.setAttribute("class", "info-tooltip");
|
yuuji@893
|
316 help.innerHTML = msg;
|
yuuji@893
|
317 elem.appendChild(help);
|
yuuji@893
|
318 setTimeout(() => {
|
yuuji@893
|
319 help.classList.add("dissolving");
|
yuuji@893
|
320 setTimeout(() => help.remove(), 3000);
|
yuuji@893
|
321 }, 1000);
|
yuuji@893
|
322 }
|
yuuji@889
|
323 function initGrphome() {
|
yuuji@889
|
324 console.log("initGrphome");
|
yuuji@889
|
325 let btn = document.querySelectorAll("button.toggle-frozen");
|
yuuji@889
|
326 if (!btn) return;
|
yuuji@889
|
327 let url = document.URL,
|
yuuji@889
|
328 mypath = url.substring(url.lastIndexOf("/"));
|
yuuji@889
|
329 if (mypath.match(/(.*)\/(.*)/)) {
|
yuuji@889
|
330 mypath = RegExp.$2;
|
yuuji@889
|
331 mypath = mypath.substring(0, mypath.lastIndexOf("?"));
|
yuuji@889
|
332 //alert("mypath="+mypath);
|
yuuji@889
|
333 } else return;
|
yuuji@893
|
334 var ja = navigator.language.match(/ja/i);
|
yuuji@889
|
335
|
yuuji@889
|
336 function toggleFrozen(e, rowid) {
|
yuuji@889
|
337 let tgt = mypath+"?blog_setfrozen+"+rowid;
|
yuuji@893
|
338 let td = e.target.parentNode;
|
yuuji@893
|
339 let tr = td.parentNode;
|
yuuji@889
|
340 fetch(tgt, {
|
yuuji@889
|
341 method: "POST",
|
yuuji@889
|
342 headers: {'Content-Type': 'text/html; charset=utf-8'},
|
yuuji@889
|
343 }).then(function(resp) {
|
yuuji@889
|
344 return resp.text();
|
yuuji@889
|
345 }).then(function(tbody) {
|
yuuji@889
|
346 try {
|
yuuji@889
|
347 var json = JSON.parse(tbody);
|
yuuji@889
|
348 } catch (e) {
|
yuuji@889
|
349 return;
|
yuuji@889
|
350 }
|
yuuji@893
|
351 let state = json.state, newstate, info;
|
yuuji@889
|
352 if (json.alert) {
|
yuuji@889
|
353 alert(json.alert)
|
yuuji@889
|
354 }
|
yuuji@889
|
355 if (state.match(/frozen/i)) {
|
yuuji@889
|
356 newstate = "凍結";
|
yuuji@893
|
357 info = ja ? newstate+"に設定しました" : 'Set Frozen';
|
yuuji@889
|
358 } else {
|
yuuji@889
|
359 newstate = null;
|
yuuji@893
|
360 info = ja ? '稼動に設定しました' : 'Set Running';
|
yuuji@889
|
361 }
|
yuuji@889
|
362 tr.setAttribute("class", newstate);
|
yuuji@893
|
363 dispInfoMomentary(info, td);
|
yuuji@889
|
364 });
|
yuuji@889
|
365 }
|
yuuji@889
|
366 for (let b of btn) {
|
yuuji@889
|
367 let rowid = null;
|
yuuji@893
|
368 let td=b.parentNode, tr = td.parentNode, fr, ru;
|
yuuji@893
|
369 ru = ja ? "動" : "Running";
|
yuuji@893
|
370 fr = ja ? "凍" : "Frozen";
|
yuuji@893
|
371 b.setAttribute('frozen-marker', fr);
|
yuuji@893
|
372 b.setAttribute('running-marker', ru);
|
yuuji@889
|
373 for (let a of tr.querySelectorAll("a[href]")) {
|
yuuji@889
|
374 if (a.getAttribute("href").match(/\?replyblog\+([0-9]+)/)) {
|
yuuji@889
|
375 rowid = parseInt(RegExp.$1);
|
yuuji@889
|
376 break;
|
yuuji@889
|
377 }
|
yuuji@889
|
378 }
|
yuuji@889
|
379 if (rowid && rowid>0) {
|
yuuji@889
|
380 b.addEventListener("click", function(e) {
|
yuuji@889
|
381 if (!btn) return;
|
yuuji@889
|
382 toggleFrozen(e, rowid);
|
yuuji@889
|
383 }, false);
|
yuuji@889
|
384 b.setAttribute("title", "稼動/凍結をその場で切り替えます\n\
|
yuuji@889
|
385 Toggle Running/Frozen ("+rowid+")");
|
yuuji@889
|
386 }
|
yuuji@889
|
387 }
|
yuuji@889
|
388 }
|
yuuji@659
|
389 function init() {
|
yuuji@659
|
390 initGrpAction();
|
yuuji@659
|
391 initBlogs();
|
yuuji@837
|
392 initFileInput();
|
yuuji@846
|
393 initTextarea();
|
yuuji@889
|
394 initGrphome();
|
yuuji@659
|
395 }
|
yuuji@586
|
396 document.addEventListener('DOMContentLoaded', init, null);
|
yuuji@586
|
397 })();
|