?レンタルサーバーで・・・
Smail Sever 解決する課題
- サーバー変数が取得できない
モジュール形式にすることでとりあえず回避
- 元号日付に対応していない
$str = strftime ("%Ex", strtotime ($strDate));
震災後
十年来、行って手を合わせたかった場所にやっと行くことができた。
往復に700km。
宮城県の大川小学校だ。
津波で死んだ人たちに会いたかったからだ。
周りは工事中で騒がしい場所ではあったが、近くに慰霊の石碑があった。
足が悪いので雪道は勘弁。車の中から目を閉じて黙祷。
色々な情景が浮かんでは消えたが、とてもとても静かだった。
震災からの10年という月日がなければ、今の僕はその場所に立ち向かえなかった。
震災後2週間目で岩手県山田町に向かった。
教科書の写真でしかみたことのない空襲の跡のような映像がカラーで目の前にあった。
自衛隊のおかげで道があり、目的地まで行くことができた。
その途中金縛りにもあった。
その後、何もくなった河原で手を合わせた夢を見た。
ドライブの途中、現実にその場所が実際にあり、再度手を合わせて帰ってきたこともある。
そしてやっとの今日だ。
遅くなったことに申しわけなく思う。
マウスストーカー
<script> class P2{ constructor(x=0,y=0){this.x=x;this.y=y} get clone(){return new P2(this.x,this.y)}//複写 add({x=0,y=0},{x:X,y:Y}=this){this.x=X+x;this.y=Y+y;return this}//加算 sub({x=0,y=0},{x:X,y:Y}=this){this.x=X-x;this.y=Y-y;return this}//減算 mul({x=0,y=0},{x:X,y:Y}=this){this.x=X*x;this.y=Y*y;return this}//乗算 div({x=0,y=0},{x:X,y:Y}=this){this.x=X/x;this.y=Y/y;return this}//除算 sMul(n=0,{x:X,y:Y}=this){this.x=X*n;this.y=Y*n;return this}//スカラー倍 } //__ //追いかける素となるもの(マウスの座標) class MousePointer extends P2 { constructor (x, y) { super (x, y); } handleEvent (event) { this.x = event.clientX + window.pageXOffset; this.y = event.clientY + window.pageYOffset; } static create (view = document) { let obj = new this (); view.addEventListener ('mousemove', obj, false); return obj; } } //__ //追いかけるもの class Stalker extends P2 { constructor (target, images, pointer, option = {}) { super (pointer.x, pointer.y); this.target = target; this.images = images; this.pointer = pointer; this.option = Object.assign ({}, this.constructor.getDefaultOption (), option); this.disabled = false; this.chase (); } chase () { const { PI, floor:int, atan2 } = Math; if (this.disabled) return; let dp = this.pointer.clone.sub (this), n = 360 / this.images.length, ang = atan2 (dp.x, -dp.y) * 180 / PI; this.add (dp.sMul (this.option.accelerator)); this.locate (); this.target.src = this.images[int ((360 + ang) % 360 / n)].src; requestAnimationFrame (this.chase.bind (this)); } locate () { const int = Math.floor; let p = this.option.offset.clone.add (this); Object.assign (this.target.style, { left: int (p.x) + 'px', top: int (p.y) + 'px'}); return this; } static getDefaultOption () { return { offset: new P2 (0, 0), accelerator: .9 }; } static create (imageList, pointer, option = { }) { let target = new Image, images = imageList.map (src=> Object.assign (new Image, {src})); target.src = images[0].src; Object.assign (target.style, {position: 'absolute', left: '0px', top: '0px'}); document.body.appendChild (target); return new Stalker (target, images, pointer, option); } } //__ const src = [ 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJklI+py33gYgsAymsCrVjqzXXMB4YiQpbmmaor1rpvFMvzWFf6bjm1xgv6frYdjhhMKoifpJKWerKiwpOgJRVhq1NStrPlWa9UsTVsPJfT3SZXu9aN0XK19w2O3zz6HvxuNiZYAAA7', 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJklI+py+0Po5xUhIuzziDuz3UeuAHmRIYnmppuRbovBcqzVNvrWOr7k/OJgB/hrRE0EnvGnyLZRBabMgbUJsA+p8JDdauJIo6IsFLhLF/Ei+EiwK4YzvKxrt7+4tHpvdcPGChRAAA7', 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJXlI+py+0Po2Rh2lBtxFk73nkLGIoIWZoCmh7sC1PwTI70jSn4nuy868MdAMSi8YhMEg3KpnPJfEqNiKk1YZUqss4FV6kaIsNiKjlaPJcB6nJb/B7G56oCADs=', 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJjlI+py+0Po5zUhFDhvbnt3SnfFx4AMILheaacx7Csiy1vIsu0eJu57kKQFD9gyjIkFlu0UWPJbPaUS+mUWrRCoKhmhOv9QncS8HFiTpbH6i23e32+o+s5U2yfufOykv8P6FAAADs=', 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJnlI+pywkPQZi02QhptQw/PXGdBwbi4kngqaQl65ArfLgzLdgabugb7gvxgqahbGfEvJKRJfD4a6SIpSJiqqwiW9iPVjjCfq1SsZZldp6mVWbm9mxueTk5mN57k/F5FR8l8dchSChQAAA7', 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJmlI+py+0PE4j0gFvj3dnt3y3fGCLjGHjN+QXuOins5tYMZ85AzYu4oNvxbDJQcEgsBmnI1G15aTqfS+kDar0emxpdFuLlUmbfLkpcOUmn49aaDWa+4Z7oPKm9DzV6ZOkPGCg4yFAAADs=', 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJXlI+py+0PAZwJSErtxU9vzngfWInkIlpnmbbuaLxyqsy2xt4zoutH7xMAg4KA8YhMKpcBBPMJbTqj1KOiWl1go4zts7FcXZPisbWcQKLN63H7+o7L54cCADs=', 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJflI+py+0PYwO02nthwDzr3XFSQIZeRJYmIBmp2rXuC8YtDYsjXusfb0LxcpjfMOgYvpAM5TLUcD5tCtoMx0S8tEBoIlXtFsNNcaWZNMu+3XUY517A43IwvXzP6/d8fQEAOw==' ]; let pointer0 = MousePointer.create (), pointer1 = Stalker.create (src, pointer0, {offset: new P2(20,20), accelerator: .1}), pointer2 = Stalker.create (src, pointer1, {offset: new P2(40,40), accelerator: .09}), pointer3 = Stalker.create (src, pointer2, {offset: new P2(60,60), accelerator: .08}); pointer4 = Stalker.create (src, pointer3, {offset: new P2(80,80), accelerator: .07}); pointer5 = Stalker.create (src, pointer4, {offset: new P2(100,100), accelerator: .06}); pointer6 = Stalker.create (src, pointer5, {offset: new P2(120,120), accelerator: .05}); pointer7 = Stalker.create (src, pointer6, {offset: new P2(140,140), accelerator: .04}); </script>
```
```
万年カレンダーJavaScriptで作る
万年カレンダーJavaScriptで作る
<!DOCTYPE html> <meta charset="utf-8"> <title></title> <style> table { margin: 1em 0; } thead td { font-weight: bold; } thead td, tbody td { text-align: center; border: 1px transparent solid; } tbody td:hover:not(.pDay):not(.nDay) { border: 1px #f80 solid; } tr td:first-of-type { color: red; } tr td:last-of-type { color:#099; } thead td { padding: 0 .5ex;} caption label { padding: 0 .5ex; font-size: large; font-weight: bold; } caption button { background: transparent; border-style: none; font-size: large; padding: 0; } caption .hide { display: none; } tbody td.pDay, tbody td.nDay { color: silver; font-size: small; vertical-align: top; } tbody td.nDay { color: silver; font-size: small; vertical-align: bottom; } </style> <table></table> <table></table> <table></table> <script> class Calendar { constructor (table, date, option = { }) { this.table = table; this.date = date; this.option = Object.assign ({ }, this.constructor.defaultOption (), option); this.view (); } view () { const {table, option, constructor: c } = this, {remove, getYMD, setNo, splice, toTBody, append} = c.tools (); let tbody = document.createElement ('tbody'), [y, m] = getYMD (this.current),//日付 [,, pd, pw] = getYMD (new Date (y, m, 0)),//先月末日 [,, nd, nw] = getYMD (new Date (y, m + 1, 0)),//今月末日 pn = (pw + 1) % 7,//先月の繰越す日数 nn = 6 - nw,//来月の取入れ日数 days = [ ...setNo (pn, pd - pn + 1),//連番(先月末) ...setNo (nd),//連番(今月) ...setNo (nn)//連番(翌月) ]; remove (table.children);//子要素を削除 append (table.createCaption (), option.caption);//キャプションをDOMで展開 toTBody (table.createTHead (), option.weekName);//週名を展開 toTBody (table.appendChild (tbody), [...splice (days, 7)]);//7日で区切る [...table.querySelectorAll ('caption label')] .forEach ((e, i)=> e.textContent = [y, option.monthName[m]][i]); let es = [...table.querySelectorAll ('tbody td')]; if (pn) es.slice (0, pn).forEach (e=> e.classList.add ('pDay')); if (nn) es.slice (-nn).forEach (e=> e.classList.add ('nDay')); return this; } offsetMonth (n = 0) { this.current.setMonth (this.current.getMonth () + n); this.view (); return this; } set date (dt) { const {getYMD} = this.constructor.tools (); let [y, m] = getYMD (dt); this.current = new Date (y, m, 1); this._date = dt; } getDate (td) { const {zp, getYMD} = this.constructor.tools (); let [y, m, _, w] = getYMD (this.current), d = Number (td.textContent), ymd = [y, m+1, d], str = ymd.map ((a,b)=>zp(a,[4,2,2][b])).join ('-'); return [new Date (y, m, d), str, ...ymd, w]; } event (td) { if (td) { let cbFunc = this.option.cbFunc, args = this.getDate (td); if ('function' === typeof cbFunc) cbFunc.apply (this, args); if (this.option.clipboard) navigator.clipboard.writeText (args[1]).then(()=> console.log (args)); } } handleEvent (event) { let e = event.target, p; switch (n.nodeName) { case 'BUTTON' : if (p = e.closest ('caption')) { let btNo = [...c.querySelectorAll('button')].indexOf (e); return this.offsetMonth ([-12, -1, 1, 12][btNo]); } break; case 'TD' : if (p = e.closest ('tbody')) return this.event (e); break; } } static tools () { return { zp: (a,b=2)=>String(a).padStart(b,'0'), remove: a=>[...a].map(a=>a.remove()), getYMD: a=>['FullYear','Month','Date','Day'].map(b=>a['get'+b]()), setNo: function*(a,b=1,c=1,d=0){for(;d<a;d+=c)yield b+d}, splice: function*(a,b=1){while(a.length)yield a.splice(0,b)}, append: ((f=(a,b,c,{tag:T,child:C,...O}=b)=>Array.isArray(b)?b.reduce((a,b)=>f(a,b),a):(Object.assign(a.appendChild(c=document.createElement(T)),O),C&&f(c,C),a))=>f)(), toTBody: (a,ary)=>{ const reg = /^(#?)(?:\[(\d+)?(?:\,(\d+)?)?\])?\s*(?:(.+)\s)*\s*(?:([+-]?(?:[1-9][0-9]{0,2}(?:\,?[0-9]{3})*)?(?:0?(?:\.\d*))?)|(.+))?$/, setAttr = (a,b,O=Object)=>O.assign(a,O.fromEntries(O.entries(b).filter(c=>'undefined'!==typeof c[1]))); for (let row of ary) { let tr = a.insertRow (); for (let cell of row) { let [,thd, colSpan, rowSpan, className, num, text] = reg.exec (cell), td = tr.appendChild (document.createElement (thd ? 'th': 'td')), attr = {colSpan, rowSpan, className, textContent: text || num || ''}; if (num != null) className += 'num'; setAttr (td, attr); tr.appendChild (td); } } } }; } static defaultOption () { return { weekName: [['Sun','Mon','Tue','Wed','Thu','Fri','Sat']], monthName: ['January','February','March','April','May','June','July','August','September','October','November','December'], caption: [ { tag: 'button', type: 'button', textContent: '⏪', className: 'hide' }, { tag: 'button', type: 'button', textContent: '<' }, { tag: 'label', className: 'hide' }, { tag: 'label'}, { tag: 'button', type: 'button', textContent: '>'}, { tag: 'button', type: 'button', textContent: '⏩', className: 'hide' } ], cbFunc: null, clipboard: true, }; } static create (table = document.createElement ('table'), date = new Date, option = { }) { const calendar = new this (table, date, option); table.addEventListener ('click', calendar, false); return calendar; } } const TABLE = document.querySelectorAll ('table'), [a, b, c] = Array.from (TABLE, t=> Calendar.create (t)); b.offsetMonth (+1); c.offsetMonth (+2); </script>
アロー関数で再帰
JavaScript アロー関数で再帰
有ろうことか!アロー関数で再帰ができるとは知らなかった。
let func = ((cbFunc = arg=> { ... }) => cbFunc)()
const fibonacci = ((fb= n=> n > 1 ? fb(n-2) + fb(n-1): n)=> fb)(); console.log(fibonacci (9));//-> 34 </script>
アロー関数(n=> n > 1 ? n * fb(n-1): 1)を変数(fb)に代入し、
その代入した関数を即時関数によって関数(fb)として返すように
代入(fibonacci )する
これは思いつかなかった
オブジェクトをDOMにして追加する。(かなり短い)
// append (document.body, {tag: 'h1', textContent: 'Test', child:[{tag:'label', textContent: 'version'}]); // <h1>Test<label>version</label></h1> let append = ((f=(a,b,c,{tag:T,child:C,...O}=b)=>Array.isArray(b)?b.reduce((a,b)=>append(a,b),a):(Object.assign(a.appendChild(c=document.createElement(T)),O),C&&append(c,C),a))=>f)();
原形
それにしても document.createDocumentFragment は長い。
function append (e, arg) { let fgm = document.createDocumentFragment (); if (Array.isArray (arg)) { arg.forEach (a=> append (fgm, a)); } else if (Object === arg.constructor) { let {tag, child, ...attr} = arg, e = Object.assign (fgm.appendChild (document.createElement (tag)), attr); if (child) append (e, child); } e.appendChild (fgm); return e; }
時間を遅らせてコールバック関数を起動する
時間を遅らせてコールバック関数を起動する
class DelayCBFunc { constructor (cbfunc, time = 500 /*ms*/) { this.cbfunc = cbfunc; this.time = time; this.tmid = null; this.disabled = false; } restart (...args) { this.stop (); this.tmid = setTimeout (this.cbfunc.bind(this,...args), this.time); } stop () { if (this.tmid) this.tmid = clearTimeout (this.tmid); } } //-- function delayAlert (e) { alert (e.value + 'でした'); } const DA = new DelayCBFunc (delayAlert, 1000); const TG = document.querySelector ('input[type="serach"]'); function handle (event) { DA.restart (event.target); } TG.addEventListener ('input', handle, false);//1秒間に入力がないとアラートする
change イベントを遅らせて発火させる。(input イベントを監視する)
// input イベントを監視して、変更があったら change イベントを発火させる // コールバックを指定すると change イベント直前に実行できる class delayChangeEvent { constructor (target, delayTime, cbFunc) { this.target = target; this.delay = delayTime; //遅延時間(ms) this.cbFunc = cbFunc; //その時に実行する関数 this.disabled = false; //この値を true にすると実行されなくなる this.timeId = null; //setTimeout で使用する this.value = target.value; // input event を監視する target.addEventListener ('input', this, false); } //イベントハンドラ handleEvent (event) { if (this.disabled) return; switch (event.type) { case 'input' : //input event を監視する if (this.timerId) clearTimeout (this.timerId);//タイマーを解除 this.timerId = setTimeout (this.execute.bind (this), this.delay);//タイマー設定 break; } } //change イベントを発火させる execute () { if (this.disabled) return; this.timerId = null; if (this.value !== this.target.value) { let e = this.target, event = e.ownerDocument.createEvent ('HTMLEvents'); event.initEvent ('change', true, true); //change イベントの前に コールバックを実行する if ('function' === typeof this.cbFunc) this.cbFunc (e); this.target.dispatchEvent (event); } } // static create (target, delayTime = 300, cbFunc = null) { if (! target) throw new Error ('要素がありません'); return new this (target, delayTime, cbFunc); } }
SELECTの連携を今更ながら書いてみた
寺尾で答えてみた
https://teratail.com/questions/310078
なぜか面白くない。
提示されたコードは見難い。なので最初から自分で好きなように書いた方が楽。
汚いコードを指摘してあげるより、私はこれが楽だ。
本当の意味でのショートコーディングは奥が深い。
オブジェクト指向の書き方も奥が深い。
アンカータグの name 属性は無くなっていたのか!知らなかった。
ちょっとだけ賢くなった。
<!DOCTYPE html> <html lang="ja"> <meta charset="UTF-8"> <title>連携SELECT</title> <style> li > ol { margin: 0; padding: 0; } </style> <body> <ol> <li>第一選択肢 <p> <select name="cat1"> <option value="" selected>選択してください</option> <option value="0">a</option> <option value="1">b</option> </select> </p> <li>第二選択肢 <ol> <li> <select name="cat2"> <option value="">選択してください</option> <option value="0">a-a</option> <option value="1">a-b</option> </select> <li> <select name="cat2"> <option value="">選択してください</option> <option value="2">b-a</option> <option value="3">b-b</option> </select> </ol> <li>第三選択肢 <ol> <li> <select name="cat3"> <option value="">選択してください</option> <option value="1">a-a-a</option> <option value="2">a-a-b</option> </select> <li> <select name="cat3"> <option value="">選択してください</option> <option value="3">a-b-a</option> <option value="4">a-b-b</option> </select> <li> <select name="cat3"> <option value="">選択してください</option> <option value="5">b-a-a</option> <option value="6">b-a-b</option> </select> <li> <select name="cat3"> <option value="">選択してください</option> <option value="7">b-b-a</option> <option value="8">b-b-b</option> </select> </ol> <li id="cat4">結果 <ol> <li>まだ全て選択されていません</li> <li><a href="exp.co.jp#a-a-a">a-a-a</a> <li><a href="exp.co.jp#a-a-b">a-a-b</a> <li><a href="exp.co.jp#a-b-a">a-b-a</a> <li><a href="exp.co.jp#a-b-a">a-b-b</a> <li><a href="exp.co.jp#b-a-a">b-a-a</a> <li><a href="exp.co.jp#b-a-b">b-a-b</a> <li><a href="exp.co.jp#b-b-a">b-b-a</a> <li><a href="exp.co.jp#a-a-a">b-b-b</a> </ol> </ol> <hr> <ol> <li>第一選択肢 <p> <select name="chk0"> <option value="" selected>選択してください</option> <option value="0">a</option> <option value="1">b</option> </select> </p> <li>第二選択肢 <ol> <li> <select name="chk1"> <option value="">選択してください</option> <option value="http://www.xxx.co.jp#AA">a-a</option> <option value="http://www.xxx.co.jp#AB">a-b</option> </select> <li> <select name="chk1"> <option value="">選択してください</option> <option value="http://www.xxx.co.jp#BA">b-a</option> <option value="http://www.xxx.co.jp#BB">b-b</option> </select> </ol> </ol> <script> class A { constructor (name) { this.name = name; this.reg = new RegExp ('^'+ name + '(\\d+)$'); this.next (document.querySelector (`*[name^="${name}"]`)); } next (e) { let r; if (r = this.reg.exec (e.name)) this.nextStage (this.name + (Number (r[1]) + 1), Number (e.value || "-1")); } nextStage (name, no) { let es = document.querySelectorAll (`*[name="${name}"], #${name}>ol>li`), n = no < 0 ? 0: no; es.forEach ((e, i)=> { if ('select-one' === e.type) { e.disabled = no != i; e.selectedIndex = 0; } let li = e.closest ('li'); if (li) li.style.display = n == i ? 'block': 'none'; }); if (es[0]) this.next (es[0]); } handleEvent ({target: e}) { this.next (e); } } class B { constructor (...select) { this.select = select; } handleEvent ({target: e}) { if (this.select.includes (e) && e.value) if (confirm (e.value + 'に移動します')) location.href = e.value; } } //_____ document.addEventListener ('change', new A ('cat'), false); document.addEventListener ('change', new A ('chk'), false); document.addEventListener ('change', new B (...document.querySelectorAll ('select[name="chk1"]')), false); </script>