Mercurial > hgrepos > hgweb.cgi > s4
changeset 898:411ce55c0dae
AJAX posting and PJAX file-viewer initially introduced.
author | HIROSE Yuuji <yuuji@gentei.org> |
---|---|
date | Sat, 02 Jan 2021 15:15:03 +0900 |
parents | 3d437261edca |
children | a4ad4101064d |
files | examples/common/default/default.css s4-blog.sh s4-main.js scripts/s4-sns.case |
diffstat | 4 files changed, 449 insertions(+), 42 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/common/default/default.css Thu Dec 31 10:31:13 2020 +0900 +++ b/examples/common/default/default.css Sat Jan 02 15:15:03 2021 +0900 @@ -4,6 +4,9 @@ body {background: #eff; margin: 2px; padding: 6px;} h2, h3, hr {clear: both;} *.warn {color: red;} +*.warnbg {background: red;} +*.hidden {visibility: hidden;} +*.border {border: 1px solid #113;} div.topmenu { margin: 0; padding: 0; width: 100%; height: 2em; } @@ -35,7 +38,9 @@ table.td2r td:nth-child(2) {text-align: right;} table.td3r td:nth-child(3) {text-align: right;} table.td3rr td:nth-child(n+3) {text-align: right;} -table.td3evw th:nth-child(2n+4) {background: white;} +table.td3evw th:nth-child(2n+4), span.textdigest { + background: white; +} table.thl th {text-align: left;} span#reverse {background: white; padding: 0 0 0 0.4ex; border: outset;} @@ -165,6 +170,24 @@ table.mini th, table.mini td {text-align: justify;} table.mini td, table.mini th {padding: 1px 0.5ex; min-width: 1em;} table.mini {margin-left: 1em; border-left: 2px solid #686;} +div.pjaxview, div.pjaxview2 { + position: fixed; top: 1ex; left: 0; width: 9vw; height: 9vh; + background: #ffffee; border: 1px double navy; border-radius: 2em; + z-index: 7; +} +div.pjaxview2 { + width: 100vw; height: 95vw; transition: 0.5s; +} +div.pjaxview iframe { + width: 98%; height: 90%; object-fit: scale-down; +} +div.pjaxview p { + padding: 0.5ex; text-align: left; margin: 0 2em; + white-space: nowrap; overflow: hidden; +} +div.pjaxview p button { font-size: large; padding: 0 1em;} +div.pjaxview p button { background: #eeeee0; } +div.pjaxview p button:focus { background: #fffff8; } /* "visibility: collapse" not working on chromium browser */ div.noprofimg tr.profimg {visibility: collapse; display: none;} @@ -393,9 +416,13 @@ border-radius: 1em; border: double 5px blue; min-width: 10em; right: 0; bottom: 0; } -.dissolving { - opacity: 0; transition: 3.0s; +.dissolving {opacity: 0; transition: 3.0s;} +.emerging {opacity: 1; transition: 3s;} +span.loading, input#c:disabled { + visibility: visible; transform: rotateX(3600deg); transition: 30s; + display: inline-block; } +span.loading {padding: 0 1em;} /* * PR Web
--- a/s4-blog.sh Thu Dec 31 10:31:13 2020 +0900 +++ b/s4-blog.sh Sat Jan 02 15:15:03 2021 +0900 @@ -178,6 +178,7 @@ fi fi fi + err "blog_showentry Entered: `gdate +%S.%03N` blogrowid=$rowid" blog_notify=`getvalbyid blog notify "$rowid"` blog_team=`blog_getteam "$rowid"` blog_mode=`getvalbyid blog mode "$rowid"` @@ -201,6 +202,12 @@ THEN '' ELSE 'Unreadable' END" + elif [ x"$blog_mode" = x"report-closed" ]; then + F_UNREADABLE="CASE + WHEN author = '$user' + THEN '' + ELSE 'Unreadable' + END" else F_UNREADABLE="'Unreadable'" fi @@ -226,6 +233,21 @@ #err id=$id #err "select val from $ts where key='title' and id='$id';" + ## Parse control sequence + nlimit=$listartlimit + case "$control" in + n:[Aa][Ll][Ll]) + unset nlimit ;; + n:*) + nlimit=${control##*:} + nlimit=${nlimit%%[!A-Z0-9a-z_]*} + ;; + f:[Aa][Ll][Ll]) ;; + f:2???-??-??*) # f:2020-12-27T08:02:43 + fetch=${control#f:} + fetch_ajax=`echo "'$fetch'"|tr T ' '` + esac + err control=$control fetch_ajax=$fetch_ajax #(1)Display root article cat<<EOF <form class="replyblog" action="$myname?replyblog+${rowid}#bottom" method="POST" enctype="multipart/form-data"> @@ -271,18 +293,21 @@ EOF if test -s $midfile && IFS='|' read edit ctime hexhead blogtype < $midfile then - cat<<-EOF + if [ -z "$fetch_ajax" ]; then # UUUUU + + cat<<-EOF <tr><td>${edit:+$href }$ctime $blogtype $href2${edit:+$href3} $href4 $href5</td></tr> <tr class="preface${frozen_class:+ }$frozen_class"> <td>`echo "$hexhead"|unhexize|htmlescape|hreflink|minitbl`</td></tr> </table> EOF - case "$blogtype" in - "クイズ"|"XXXX集計") - echo "${blogtype}モードは本人と管理者の書き込みのみが表示されます。" - ;; - esac | html p 'class="warn"' + case "$blogtype" in + "クイズ"|"XXXX集計") + echo "${blogtype}モードは本人と管理者の書き込みのみが表示されます。" + ;; + esac | html p 'class="warn"' + fi # UUUUU if [ x"$blogtype" = x"クイズ" -o x"$blogtype" = x"XXXX集計" ]; then if $isgroup; then # Failsafe to query timeout @@ -307,16 +332,7 @@ echo "時間をおいて繋いでください(Please visit later)." | html p return fi - ## Parse control sequence - nlimit=$listartlimit - case "$control" in - n:[Aa][Ll][Ll]) - unset nlimit ;; - n:*) - nlimit=${control##*:} - nlimit=${nlimit%%[!A-Z0-9a-z_]*} - ;; - esac + lkhome="<a href=\"$myname?home" lke='">' lkedit="<a href=\"$myname?editart" hlink="$myname?home" elink="$myname?editart" @@ -392,7 +408,8 @@ $cond_qz) a LEFT JOIN a_s s - ON a.id=s.id; + ON a.id=s.id + ${fetch_ajax:+WHERE s.TIME > $fetch_ajax}; EOF if [ $? -ne 0 -a ! -s $midfile ]; then echo "時間をおいてください(Visit later please)." | html p @@ -426,6 +443,7 @@ else CAT=cat fi + err "blog_showentry Started: `gdate +%S.%03N` ${fetch_ajax:+ajax}" # Start blog_replies table $CAT $midfile | while IFS='|' read id edit notify uid author uname icon aid \ @@ -487,6 +505,7 @@ usecache='' tsfile=$td/$id.stamp for i in $imgids; do mrid=${i%%:*}; i=${i#*:}; sz=`size_h ${i%%:*}` + _href="href=\"$catlink+$mrid\"" fn=`echo "${i#*:}"|unhexize` fnb=$fn"(${sz})" case "$fn" in @@ -508,7 +527,7 @@ };}; then usecache=1 # Set usecache flag on cat<<-EOF - <a href="$catlink+$mrid"><img src="$outfile"> + <__UNCLICKABLE__><a $_href><img src="$outfile"> $fnb</a> EOF # !!NOTE!! Create row stamp ONLY WHEN imgcache is active @@ -522,18 +541,18 @@ cat "$outfile" \ | hexize \ | sed -e 's/\(..\)/%\1/g' \ - -e "s|^|<a href=\"$catlink+$mrid\"><img src=\"data:image/$fmt,|" \ + -e "s|^|<__UNCLICKABLE__><a $_href><img src=\"data:image/$fmt,|" \ -e "s|\$|\">$fnb</a>|" unset stampfile # img data stream is not suitable to cache echo $tm > $tsfile else # Failed to convert rm -f $outfile - echo "<a href=\"$catlink+$mrid\">$fnb</a>" + echo "<__UNCLICKABLE__><a $_href>$fnb</a>" fi fi ;; *) - echo "<__UNREADABLE__><a href=\"$catlink+$mrid\"><img src=\"$deficon\">$fnb</a>" + echo "<__UNCLICKABLE__><a $_href><img src=\"$deficon\">$fnb</a>" ;; esac done @@ -548,10 +567,18 @@ fi test -n "$stampfile" && date "+%F %T" > $stampfile fi + if [ -n "$fa" ]; then + replhref="s/a href=[^>]*>/a>/" + else + replhref="" + fi # Printing a cached row sed -e "/^<td class=/s/__NEWCLS__/$new${new:+ }/" \ -e "/^<td class=/s,__EDIT__,$editlink," \ -e "/^<__NOTIFY__>/s,,${notify:+$nt}," \ + ${replhref:+-e "/^<__UNCLICKABLE__>/$replhref"} \ + ${replhref:+-e "/^<__UNREADABLE__>/$replhref"} \ + -e "/<__UNCLICKABLE__>/s///" \ -e "/<__UNREADABLE__>/s,,${fa:+$cannotread}," \ $cachefile done @@ -589,10 +616,12 @@ `cgi_file image "" "$file_accept title=\"$filehelp\" multiple"` </td></tr> </table> -<input type="submit" value="送信" class="$blog_notify" title="$ntmode"> +<input type="hidden" name="fetchtime" value="`date +%FT%T`"> +<input type="hidden" name="filesize_max" value="$filesize_max"> +<input type="submit" id="c" value="送信" class="$blog_notify" title="$ntmode"> <input type="reset" value="リセット"></div></div> EOF - ) + ) cat<<-EOF </table> <!-- end of s4-blog:blog_showentry() main table --> <p class="update_link"><a @@ -615,6 +644,7 @@ [ -s $iconcleaner ] && query ".read '$iconcleaner'" # Record access log acclog blog $rowid + err "blog_showentry Finished: `gdate +%S.%03N` ${fetch_ajax:+ajax}" } lshandout() { @@ -1522,6 +1552,13 @@ err "blog_reply Finished: `gdate +%S.%03N` user=$user owner=[$owner] title=[$title]" } +blog_fetch() { + contenttype "text/plain; charset=utf-8"; echo + err blog_fetch: blog "$@" + blog_reply "$@" + # blog_showentry blog "$@" +} + blog_reply_article() { # Direct link to article in some blog arid=${1:-0} # Already sanitized to digits brid=`query "SELECT rowid FROM blog WHERE \
--- a/s4-main.js Thu Dec 31 10:31:13 2020 +0900 +++ b/s4-main.js Sat Jan 02 15:15:03 2021 +0900 @@ -1,5 +1,16 @@ // 愛 (function (){ + var isOlderJS; // Set in init(); + var hasTouchPad = + (navigator.maxTouchPoints && navigator.maxTouchPoints >0); + var myurl = document.URL, + mypath = myurl.substring(myurl.lastIndexOf("/")); + var art_m_list = []; + if (mypath.match(/(.*)\/(.*)/)) { + mypath = RegExp.$2; + mypath = mypath.substring(0, mypath.lastIndexOf("?")); + //alert("mypath="+mypath); + } function collectElementsByAttr(elm, attr, val) { var e = document.getElementsByTagName(elm); if (!e) return null; @@ -67,6 +78,325 @@ textarea.value = lines.join("\n"); } } + function registPjaxViewers(aHrefList) { + // if (isOlderJS) return; + let apos=art_m_list.length; + for (let a of aHrefList) { + let href = a.getAttribute("href"); + let localvar = apos; + let td = a.parentNode, + tr = td.parentNode, + id = td.id, + text = td.textContent, + author = tr.getElementsByTagName("a"); + if (author) author = author[0].getAttribute("title"); + if (href.match(/\?showattc\+article_m\+([0-9+])/)) { + if (td.innerHTML.match(/x読み取り不可/)) { + a.removeAttribute("href"); + continue; + } + let url = RegExp.lastMatch; + // console.log("pjaxView(e, "+href+", "+apos+")"); + a.addEventListener("click", function(e) { + // Shoud use closure local variable: localvar + pjaxView(e, href, localvar); + }, false); + apos++; + art_m_list.push({ + url: href, id: id, author: author, text: text + }); + } + } + } + var ajaxSubmit; + function replAddNews(newtable) { + let newids = [], idlist=[]; + let getArticleID = function (td) { + return parseInt(td.parentNode.getElementsByTagName("td")[1].id); + } + for (let i of newtable.querySelectorAll("td.repl")) + newids.push(i); + newids = newids.sort((a,b)=> { + return (getArticleID(a) - getArticleID(b)); + }); + for (i of newids) + idlist.push(getArticleID(i)); + console.log("IDList="+idlist.join()); + let cnt=0; + let current = collectElementsByAttr("td", "class", "repl"), + ncur=0, n, icur=0, o, oid, nid, otr; + current = document.querySelectorAll('td[class="repl"]'); + let last=current[current.length-1], + tbody = last.parentNode.parentNode; + // Now reconstruct articles with merge-sort like method + outer: for (; ncur<newids.length; ncur++) { + n = newids[ncur]; + if (!n.id) continue; + nid = parseInt(n.id); + if (nid<=0) continue; + let ntr = n.parentNode; + for (; icur<current.length; icur++) { + o = current[icur]; + otr = o.parentNode; + oid = getArticleID(o); + if (!oid || oid=="") continue; + if (oid >= nid) { + ntr.getElementsByTagName("td")[0].classList.add("new"); + tbody.insertBefore(ntr, otr); + if (oid==nid) otr.remove(); + cnt++; + continue outer; + } + } + // Append absolutely new articles. + ntr = n.parentNode; + ntr.getElementsByTagName("td")[0].classList.add("new"); + tbody.appendChild(ntr); + registPjaxViewers(ntr.querySelectorAll("a[href]")); + ntr.classList.add("dissolving"); + ntr.scrollIntoView({behavior: "smooth"}); + setTimeout(() => { + ntr.classList.remove("dissolving"); + ntr.classList.add("emerging"); + }, 100); + cnt++; + } + ajaxSubmit.value = ajaxSubmit.back; + ajaxSubmit.disabled = false; + console.log("Update "+cnt+"rows"); + return cnt; + } + + function warnFileSize(form) { + let szmax = form.querySelector('input[name="filesize_max"]').value; + if (!szmax || szmax=="") return; + szmax = parseInt(szmax); + if (szmax <= 0) return; + // szmax = 10000 + let ng = "", rcval=false, fileexists=false; + for (let f of form.querySelectorAll('input[type="file"]')) { + let thiserr = false + for (let i of f.files) { + fileexists = true; + let fn = i.name, sz = i.size; + console.log("max="+szmax+", fn="+fn+", sz="+sz); + if (sz > szmax) { + thiserr = true; + ng += ((ng>"" ? ", " : "")+fn) + } + } + thiserr ? f.classList.add("warnbg") : f.classList.remove("warnbg"); + } + if (ng>"") { + rcval = "File-size Limit Error: "+ng+"\n"+ + "Should be less than "+szmax+"bytes.\n"+ + szmax+"バイト未満にしてください" + alert(rcval); + } + if (form.text.value == "") { + let w; + if (fileexists) + w = "Fill the text area\n" + + "添付したファイルに関する説明を入れてください。"; + else + w = "Enter your comment!\n何か書き込んでね!"; + alert(w); + rcval = (rcval || w); + form.text.classList.add("warnbg"); + setTimeout(() => {form.text.classList.remove("warnbg");}, 2000) + } + return rcval; + } + function ajaxPost(e) { + e.preventDefault(); + let rowid; + if (!myurl.match(/replyblog\+([0-9]+)/)) return; + rowid = RegExp.$1 + let myform = document.querySelector("form.replyblog"); + if (warnFileSize(myform)) return; + ajaxSubmit = e.target; + ajaxSubmit.back = ajaxSubmit.value; + ajaxSubmit.value = "送信中"; + ajaxSubmit.blur(); + ajaxSubmit.disabled = true; + let data = new FormData(myform), + fetchtime = data.get("fetchtime"); + if (!fetchtime || fetchtime=="") return; + ///*XX*/fetchtime = "2020-06-14T00:00:00";data.set("fetchtime", fetchtime) + let act = mypath+"?blog_fetch+"+rowid+"+f:"+fetchtime; + + function respUpdate(tbody) { + let div = document.createElement("div"), form, newform; + try { + div.innerHTML = tbody; + form = div.querySelector("form"); + } catch (er) { + alert("Cannot parse fetch data"); + return; + } + let update = replAddNews(form); + let dispelem = myform.querySelector("textarea").parentNode; + newform = new FormData(form); + myform.reset(); + myform.text.value = ''; + myform.fetchtime.value = newform.get("fetchtime"); + myform.id.value = newform.get("id"); + if (update && update > 0) { + let s = update + " new article" + + (update>1 ? "s" : "") + " posted"; + dispInfoMomentary(s, dispelem); + } + } + fetch(act, { + method: "POST", body: data, + credentials: "include" // For older firefox + }).then((resp) => { + return resp.text(); + }).then((tbody) => { + respUpdate(tbody); + }) + } + function pjaxView(ev, url, mynum) { + ev.preventDefault(); + let box = document.createElement("div") + box.setAttribute("class", "pjaxview"); + let p1 = document.createElement("p"), + bt = document.createElement("button"), + sl = document.createElement("button"), + sr = document.createElement("button"), + loading = document.createElement("span"), + info = document.createElement("p"); + info1 = document.createElement("span"); + info2 = document.createElement("span"); + iframe = document.createElement("iframe"); + var curpos = mynum; + var historyBase = history.length; + + function _setPjaxCurposInfo() { + let len = art_m_list.length; + let cur = art_m_list[curpos] + info1.textContent = (1+curpos)+" of "+len+" article #"+cur.id+ + (cur.author ? " by "+cur.author : "") + ":"; + info2.textContent = cur.text.trim(); + info2.setAttribute("class", "border textdigest"); + } + function _resetPjax() { + // All we can do surely is to back 1 page, + // because we cannot move to desirable entry of history list. + history.back(); + } + function setSwipeAct(iframe) { + // We cannot use DOMContentLoaded nor iframe.contentWindow here. + // PDF.js does not construct contentWindow...? + iframe.addEventListener("load", () => { + loading.classList.remove("loading"); + if (!hasTouchPad) return; + let ifm = iframe.contentDocument; + let startX, moveX, thresh = 100; + ifm.addEventListener("touchstart", (e) => { + e.preventDefault(); + startX = e.touches[0].pageX; + }, false); + ifm.addEventListener("touchmove", (e) => { + e.preventDefault(); + moveX = e.touches[0].pageX; + }, false); + ifm.addEventListener("touchend", (e) => { + if (startX < moveX && startX + thresh < moveX) { + switchTo(e, -1); + } else if (startX > moveX && startX - thresh > moveX) { + switchTo(e, +1); + } + }, false); + }, false); + + } + function switchTo(e, direction) { + e.preventDefault(); + let len = art_m_list.length, cur, newpos, url; + newpos = (curpos+len+direction)%len; + if (curpos == newpos) return; // No need to switch to same one + curpos = newpos; + cur = art_m_list[curpos]; + url = cur.url; + // We should remove iframe once to preserve history Object + // https://inthetechpit.com/2019/04/20/update-iframe-without-affecting-browser-history/ + let parent = iframe.parentNode; + // alert("D = "+direction); + iframe.remove(); + parent.appendChild(iframe); + try { + loading.classList.add("loading"); + iframe.src = url; + // iframe.contentDocument.location.replace(url); + // location.replace cannot be used because PDF viewer.js + // does not have iframe.contentDocument + } catch (err) { + alert("Cannot load "+src+" : "+err.name); + } + _setPjaxCurposInfo(); + setSwipeAct(iframe); + } + function switchToByKey(e) { + // alert("KEY="+e.key); + switch (e.key) { + case "ArrowLeft": + switchTo(e, -1); break; + case "ArrowRight": + switchTo(e, +1); break; + case "Escape": + history.back(); + } + } + // <div><p> + // <button> << </button><button>Dismiss</button><button> >> </button> + // </p><p><span> info1 </span> <span> info2 </span></p> + // <iframe src="..."></iframe> + // </div> + // ==> [ << ][Dissmiss][ >> ] + // ==> ## of ## article #xxx by AUTHOR + sl.textContent = " << "; + sr.textContent = " >> "; + sl.addEventListener("click", (e) => {switchTo(e, -1);}); + sr.addEventListener("click", (e) => {switchTo(e, +1);}); + sl.setAttribute("title", "to="+(mynum-1)); + sr.setAttribute("title", "to="+(mynum+1)); + document.body.appendChild(box); + bt.textContent = "Click to dismiss / もどる"+mynum; + + box.appendChild(p1); + p1.appendChild(sl); p1.appendChild(bt); p1.appendChild(sr); + p1.appendChild(loading); + info.appendChild(info1); info.appendChild(info2); + loading.textContent=" Loading..."; + loading.classList.add("hidden"); + loading.classList.add("loading"); + box.appendChild(info); + iframe.src = url; + + document.addEventListener("keydown", switchToByKey); + //box.addEventListener("click", (e) => {_resetPjax();}); + bt.addEventListener("click", (e) => {_resetPjax();}); + // dp.addEventListener("click", (e) => {_resetPjax();}); + info.addEventListener("click", (e) => {_resetPjax();}); + box.appendChild(iframe); + + setSwipeAct(iframe); + + _setPjaxCurposInfo(); + bt.focus(); + setTimeout(() => {box.classList.add("pjaxview2");}, 10); + // Finally update history stack + if (history.pushState) { + let h = location.href.replace(/#.*/, '')+"#pjaxview"; + history.pushState({url: h}, null, h); + window.addEventListener("popstate", (e) => { + if (box) { + box.remove(); box = null; + } + }, false); + } + } function reverseChecks() { var names = collectElementsByAttr("input", "name", "usel"); for (let u of names) { @@ -75,7 +405,6 @@ } function renumberOL(str, start) { var stra = str.split("\n"); - for (var i=1; i<stra.length; i++) { if (stra[i].match(/^[1-9][0-9]*\. /)) { let orig=stra[i]; @@ -192,9 +521,9 @@ } } function helpMarkdown(e) { - switch (e.keyCode) { - case 8: helpMarkdownBS(e); break; - case 13: helpMarkdownEnter(e); break; + switch (e.key) { + case "Backspace": helpMarkdownBS(e); break; + case "Enter": helpMarkdownEnter(e); break; } } /* Init event listeners */ @@ -212,7 +541,10 @@ var inpf = ih.substring(ih.indexOf("<input")), newi = "<br>"+inpf.substring(0, inpf.indexOf(">")+1); i.insertAdjacentHTML("afterend", newi) - // alert(newi); + i.nextSibling.nextSibling.addEventListener('change', () => { + // next==br next.next==input[type=file] + warnFileSize(document.forms[0]); + }); } } } @@ -248,12 +580,28 @@ var check = collectElementsByAttr("input", "name", "notifyto"); if (check) for (let i of check) { - i.addEventListener("click", insertRedirect, null); + i.addEventListener("click", insertRedirect, false); } - for (let i of document.getElementsByTagName("a")) + for (let i of document.querySelectorAll("a[href]")) if (i.getAttribute("href").match(/^#[0-9]+$/)) if (RegExp.lastMatch == i.innerHTML) - i.addEventListener("click", insertRedirect, null) + i.addEventListener("click", insertRedirect, false) + for (let i of document.querySelectorAll('input[value="送信"]')) { + // let b = document.createElement("button"); + let b = i; + b.value = "送信!"; + console.log("b="+b+", tc="+b.textContent); + b.addEventListener("click", ajaxPost, false); + // i.insertAdjacentElement('afterend', b); + } + for (let f of document.querySelectorAll('input[type="file"]')) { + let form = document.forms[0]; + f.addEventListener('change', (e) => { + warnFileSize(form); + }, false) + } + // Hack article_m links + registPjaxViewers(document.querySelectorAll("a[href]")); } function initGrpAction() { var rev = document.getElementById("reverse"); @@ -323,13 +671,6 @@ function initGrphome() { console.log("initGrphome"); // (1)Setup Frozen State Changing Button - let url = document.URL, - mypath = url.substring(url.lastIndexOf("/")); - if (mypath.match(/(.*)\/(.*)/)) { - mypath = RegExp.$2; - mypath = mypath.substring(0, mypath.lastIndexOf("?")); - //alert("mypath="+mypath); - } else return; var ja = navigator.language.match(/ja/i); function toggleFrozen(e, rowid) { @@ -339,6 +680,7 @@ fetch(tgt, { method: "POST", headers: {'Content-Type': 'text/html; charset=utf-8'}, + credentials: "include" }).then(function(resp) { return resp.text(); }).then(function(tbody) { @@ -420,6 +762,7 @@ } } function init() { + isOlderJS = !("insertAdjacentElement" in document.body); initGrpAction(); initBlogs(); initFileInput();
--- a/scripts/s4-sns.case Thu Dec 31 10:31:13 2020 +0900 +++ b/scripts/s4-sns.case Sat Jan 02 15:15:03 2021 +0900 @@ -46,7 +46,7 @@ echo "Refresh: 0; $newurl"; echo exit 0 ;; - lshandout|lshandoutall|gethandout|gethandoutcsv|gethandoutcsv2|blogseen|getteamcsv|blog_setfrozen) + lshandout|lshandoutall|gethandout|gethandoutcsv|gethandoutcsv2|blogseen|getteamcsv|blog_setfrozen|blog_fetch) case "$stage" in lshandout*|blogseen*) contenttype; echo ;; esac