オブジェクト型の合成
オブジェクト型の合成(merge)
配列同士なら concat する
function merge (a, ...args) {
let r = Object.assign ({ }, a);
for (let obj of args) {
for (let [k, o] of Object.entries (obj)) {
switch(Object.prototype.toString.call(o).slice(8,-1)) {
case 'Object': r[k] = merge (r[k]||{}, o); break;
case 'Array': r[k] = Array.isArray (r[k]) ? r[k].concat(o): o; break;
case 'Date': r[k]= new Date(o); break;
default: r[k]=o;break;
}
}
}
return r;
}
短く
const merge=(a,...b)=>{let r=Object.assign({},a);for(let c of b)for(let[k,o,t=Object.prototype.toString.call(o).slice(8,-4)]of Object.entries(c))r[k]='Obj'==t?merge(r[k]||{},o):'Ar'==t?r[k]=Array.isArray(r[k])?r[k].concat(o):o:'D'==t?new Date(o):o;return r}再帰で呼び出す場合関数名が被るのでアロー関数にして
const merge=((
M=(a,...b)=>{
let r=Object.assign({},a);
for(let c of b)
for(let[k,o,t=Object.prototype.toString.call(o).slice(8,-4)]of Object.entries(c))
r[k]='Obj'==t
? M(r[k]||{},o)
: 'Ar'==t
? r[k]=Array.isArray(r[k])?r[k].concat(o):o
: 'D'==t
? new Date(o)
: o
return r;
})=>M)();
renge 関数を短く(最小じゃね?)
const range=(b,e,s=b<e?1:-1,_=[],i=b)=>{for(;_.push(i),i!=e;i+=s);return _};
俺流 sprintf 関数を作る
const
sprintf = (...args)=>{
let j=1;return args[0].replace (/\%(?:(\d+)\$)?(?:\'(.))?(0)?([1-9]|[1-9][0-9]*)?([ds])/g,(_,i=j++,c=" ",z=c,l=0,t,u,v,s=''+args[i])=>s.padStart(Math.max(l,s.length),z))
};
カレンダーを作る
<!DOCTYPE html>
<style>
td {
text-align: right;
line-height: 130%;
}
tr td:first-child {
color: red;
}
tr td:last-child {
color:blue;
}
tr td[colSpan]{
text-align: center;
color: green;
padding-top:2ex;
}
</style>
<body>
<table id="T"></table>
<script>
let dt = new Date;
let y = dt.getFullYear (), m = dt.getMonth ()+1;
for (let i = 0; i < 5; i++) {
T.append (calendar (y, m+i))
}
function calendar (y, m, t = document.createElement ('tbody')) {
let A=Array,B='......',C=new Date(y,m,0),
D=A.from(A(C.getDate()),(_,i)=>i+1),
E=[[...D.splice(-C.getDay()-1),...B].slice(0,7)];
while(D[0])E.unshift(D.splice(-7));
E[0] = [...B, ...E[0]].slice(-7);
E.unshift([`${y} / ${C.getMonth()+1}`]);
E.forEach(r=>(r.reduce((_,c)=>((_.insertCell()).append(c),_),t.insertRow())));
t.rows[0].cells[0].colSpan=7;
return t;
}
</script>
画像フォルダのファイルを連番に書き換える
PRTFileName ('./data/*.jpg');
exit ();
//指定のディレクトリのファイル名を順序だてて再構成する(新しい順)
function PRTFileName ($path, $format = 'img_%04d.jpg', $limit = 10000) {
$files = [];
$cnt = 0;
//$pathのチェック
$info = pathinfo ($path);
if (false === is_dir($info['dirname']))
throw new Expression ('No directory!');
//ディレクトリ内のファイル名の取得と日時を配列にする
foreach (glob ($path) as $file)
$files[$file] = filemtime ($file);
//日付順でソート
arsort ($files);
//ファイル名で再構成 & ここで最大数で切り取り
$files = array_slice (array_keys ($files), 0, $limit -1);
//拡張子がtmpでリネーム
foreach ($files as &$fName) {
$f = pathinfo ($fName);
$nName = sprintf ('%s/%s.tmp', $f['dirname'], $f['filename']);
rename ($fName, $nName);
$fName = $nName;
}
//書式に従ってファイル名を書き直す
foreach ($files as $fName) {
$nName = sprintf ('%s/'.$format, $info['dirname'], $cnt++);
rename ($fName, $nName);
}
return count ($files);
}
データベースに記録するテーブルの構造を可変にしたい
データ(レコード)サイズが大きいわけではない。
テーブル構造(フィールド)を頻繁に変更するかもしれない。
ということで、JSON形式にして文字列のまま保管できるようにしたい。
HTMLのFORMの中の要素も可変にしたい
JSONを利用して(テーブル式)フォームを形成する
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title></title>
<meta http-equiv="content-language" content="ja">
<meta http-equiv="Cache-Control" content="no-cache">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="format-detection" content="telephone=no">
<link rel="stylesheet" href="form_table.css" type="text/css">
<style>
</style>
</head>
<body>
<form method="post" enctype="multipart/form-data" id="FF">
<table id="T"></table>
<button onclick="console.log($F.getValue(),FF); return false;">フォームの値を取得</button>
<input type="submit" value="submit">
</form>
<script>
const JSON = [
{title:['世帯名',{rowspan:1}], name:'SETAI'},
{title:'住所', name:'POSTCODE', attr:{placeholder:'〒'}},
{name:'ADD' },
{name:'ADD' },
{title:'電話', name:'TEL'},
{name:'TEL' },
{name:'TEL' },
{title: '性別', name:'SEIBETU', type: 'radio', option: [
['男性','man', 0,1],
['女性','woman'],
['不詳','',1,0],
]},
{title: '言語', name:'GENGO', type: 'checkbox', option: [
['PHP','PHP'],
['JavaScript','JS',1],
['BASIC','BASIC'],
]},
{title: 'IQ', name:'IQ', type: 'select', option: [
['--選択して下さい--','',0],
['頭が良い','120'],
['普通','100'],
['無理','80'],
]},
{title: '地区', name:'TIKU', type: 'datalist', option: [
'種市','小子内','有家','中野','大野',
]},
{title: 'Memo', name:'MEMO', type: 'textarea', attr:{rows:10}},
// {title: '', name:'', value: '', type: null, option: [], attr: {}},
];
class $F {
/*
独自のJSON形式で模したフォーム要素を具現化してテーブル形式にフォームを構成する
*/
static mkTable (aryArg = [], tbody = document.createElement ('tbody')) {
const E = (n,a={},c=[],e)=> (e=document.createElement(n),Object.entries(a).forEach(([a,b])=>b !== false && e.setAttribute(a,b)),e.append(...c),e);
let tr, th, attr, cnt = 0;
for (let obj of aryArg) {
let t = obj.title;
tr = tbody.insertRow ();
if (null != t) {
if (1 < cnt)
th.rowSpan = cnt;
tr.append (th = document.createElement ('th'));
if (Array.isArray (t)) {
[t, attr] = t;
Object.entries (attr).forEach (_=> th.setAttribute (..._));
}
th.textContent = t;
cnt = 1;
} else
cnt++;
this.mkInput (obj, tr.insertCell ());
}
return tbody;
}
/*
フォーム要素を生成
*/
static mkInput (mold, parent = new DocumentFragment ()) {
// Object.assign では list属性を変更できないので setAttribute を利用
const E = (n,a={},c=[],e)=> (e=document.createElement(n),Object.entries(a).forEach(([a,b])=>b !== false && e.setAttribute(a,b)),e.append(...c),e);
let {name, value = '', attr = {}, option = [], type = 'text'} = mold;
let e = [], id;
type = mold.type = type.toLowerCase ();
switch (type) {
case 'textarea' :
e.push (E ('textarea', Object.assign({name, value},attr))); break;
case 'select' :
attr.type ='select-one';
case 'select-multiple' : case 'select-one' :
e.push (E('select', Object.assign({name, value}, attr), option.map (_=> new Option (..._))));
break;
case 'checkbox' : case 'radio' :
e.push (...(option.map (([a,b,c,d=c])=>
E('label', attr, [E('input', {name, type, value:b, checked:!!c, defaultChecked:!!d}),a])))
);
break;
case 'datalist':
id = 'dl-' + name;
e.push (
E('input', Object.assign ({name, value, list:id}, attr)), //type は attr で上書き?
E('datalist', {id}, option.map(_=> new Option(_)))
);
break;
case 'image' :
e.push (E('input', Object.assign ({name, type, value, src:value}, attr)));
break;
default :
e.push (E('input', Object.assign ({name, type, value}, attr)));
break;
}
parent.append (...e);
return parent;
}
/*
フォーム要素群の値をオブジェクト型にして返す
同じname属性が複数 or select-multipleの場合 or checkbox は配列で返す
*/
static getValue (root = document.body, query = ':is(select,textarea,input)[name]:not([type="button"],[type="reset"],[type="submit"])') {
//フォームの要素の値を返す
const V = e=> {
switch (e.type) {
case'select-multiple': return [...e.selectedOptions].map(o=>o.value);
case'checkbox': if(! e.checked) return []; break;
case'radio': if (! e.checked) return; break;
}
return e.value;
};
//__
let obj = { };
for (let e of root.querySelectorAll (query)) {
let val = V (e);
let name = e.name;
if (obj.hasOwnProperty (name)) {
if (null == val) continue;
let x = obj[name];
if (null != x)
val = [].concat (x, val);
}
obj[name] = val;
}
return obj;
}
/*
*/
//オブジェクト型の値をフォーム要素群に転置
static setValue (obj , root = document.body, query = ':is(select,textarea,input)[name]:not([type="button"],[type="reset"],[type="submit"])') {
//要素に値を設置
const V = (e, val)=> {
let idx;
if (Array.isArray (val)) {//配列の場合は、転置ごとにその値を削除する
switch (e.type) {
case 'select-multiple' :
for (let op of e.options) {
idx = val.indexOf (e.value);
if (-1 < idx) {
val.splice (idx, 1);
e.selected = true;
} else
e.selected = false;
}
break;
case 'radio' : case'checkbox' :
idx = val.indexOf (e.value);
if (-1 < idx) {
val.splice (idx, 1);
e.checked = true;
} else
e.checked = false;
break;
default :
e.value = val.shift () || '';
break;
}
}
else {//転置用の値が単一ならば、複数の同じname属性の要素に同じ値を転置する
switch (e.type) {
case 'select-multiple' :
e.options.forEach (o=> o.selected = o.value == val);
break;
case 'radio' : case'checkbox' :
e.checked = e.value == val;
break;
default :
e.value = val || '';
break;
}
}
};
//__
let
val = Object.assign ({ }, obj),//copy
es = root.querySelectorAll (query);
this.reset ();
for (let e of es)
V (e, val[e.name]);
}
static reset (root = document.body, query = ':is(select,textarea,input)[name]:not([type="button"],[type="reset"],[type="submit"])') {
let es = root.querySelectorAll (query);
for (let e of es) {
switch (e.type) {
case 'select-one' : case 'select-multiple' :
for (let op of e.options)
op.selected = op.defaultSelected;
break;
case 'radio' : case 'checkbox' :
e.checked = e.defaultChecked;
break;
default :
e.value = e.defaultValue || '';
}
}
}
}
$F.mkTable (JSON,T);
$F.setValue ({MEMO: 'abc', TIKU:'中野', GENGO:['PHP','BASIC'], SEIBETU:'woman',ADD:[,2,]});
//alert(8);
$F.reset ();
</script>
ちょっと変更
*Mini PC と チューナーレスTV とで広告用看板を作る
購入するもの
- Mini PC
- TV(チューナレス)
- 壁固定金具
- 適当なHDMIケーブルと電源類(USB TypeC PB を使って必要なボルトの電源を確保できればなお吉)
Mini PC の BIOS を設定して、通電したらPCを自動起動になるように設定する
Aptio Setup - AMI
Boot -> State After G3 -> [S0 State]
他のPCの場合の参照URLhttps://hp.vector.co.jp/authors/VA022629/Manual/PageBIOS.htm
補足
- S0 PC稼働状態
- S1 省電力状態
- S2 省電力状態(CPUへの給電はオフ、チップセット給電はオン)
- S3 スリープ状態(メモリへは給電されている)
- S4 休止状態(高速スタートアップを有効にしているときのシャットダウン状態)
- S5 シャットダウン状態(完全シャットダウン)
- Firefox のリンク先の設定
>||"C:\Program Files\Mozilla Firefox\firefox.exe" http://対象となるURL --kiosk|
