オブジェクト型の合成

オブジェクト型の合成(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 _};

カレンダーを作る

<!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>

画像フォルダのファイルを連番に書き換える

PHP

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>

ちょっと変更

晴れて自由だ!

2025-03-31
早期退職をした。自由になった。あとどれくらい生きられるだろう?

普段から計画的ではない性格なのだが、春になったらドライブしようと思って車を買っていた。
とても磨きがいのある車。

さぁ、どこへ出かけようか!?

LEXUS LC500 Convertible

*Mini PC と チューナーレスTV とで広告用看板を作る

購入するもの

  1. Mini PC
  2. TV(チューナレス)
  3. 壁固定金具
  4. 適当な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 シャットダウン状態(完全シャットダウン)

Windowsを設定する

  1. とにかく余計なアプリを削除し軽量化する
  2. ブラウザを自動起動になるように設定する (以下ディレクトリを参照しFirefox のショートカットを作成する)

>||C:\Users\????\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup|

  1. Firefox のリンク先の設定

>||"C:\Program Files\Mozilla Firefox\firefox.exe" http://対象となるURL --kiosk|

適当に画面が切り替わるようなプログラムを書いて、サーバにアップする

Mini PC の余った USB端子から 5Vの電源を取り出す

  1. ケーブル&端子付き
  2. LEDライトでも買う
  3. 適当にハンダ付けしてつなぐ