<!DOCTYPE hrml>
<html lang="ja">
<meta charset="UTF-8">
<style>
h1, h2, h3, h4, h5, h6, th {
font-weight: normal;
}
h1, h2, li > em, p em { color: blue; }
section {
column-count: 2;
column-width: 390px;
}
section {
padding: 0 3ex;
}
section table {
width: 100%;
}
thead th {
background: #def;
}
tbody:first-of-type th {
background: #ddd;
}
tbody:first-of-type td {
background: #eee;
}
tbody:nth-of-type(3) th {
background: #fdd;
}
tbody:nth-of-type(3) td {
background: #fee;
}
th {
white-space: nowrap;
text-align: left;
background: #ffd;
font-size: small;
}
td {
background: #ffe;
}
td:nth-of-type(2) {
font-size: x-small;
}
code pre {
margin: 1ex 1ex 2em 3ex;
padding: 1ex 1em;
background: #def;
border: none;
border-left: 6px #0cf solid;
font: normal normal small/140% monospace;
}
h3 {
margin : 1ex 0 1ex 1em;
border-top: 2px #09c solid;
font-weight: normal;
padding: 1em 0 0 0;
line-height: 100%;
}
h4 {
font-weight: normal;
padding: .5ex;
line-height: 100%;
background: #ddf;
display: inline-block;
margin: 1ex 0 0 3ex;
}
p {
margin: 1ex 1em 0.5ex 3ex;
color: #060;
}
ul {
margin: 0.5ex 1em 1ex 3ex;
font-size: small;
}
</style>
<body>
<h1>ExpForm.js</h1>
<p>
FORM 要素を対象としたライブラリです
<input type="button" value="コードを(非)表示する" onclick="
let e = document.querySelector ('#EXPFORM');
e.style.display = 'block' === e.style.display ? 'none': 'block';
">
</p>
<div id="EXPFORM" style="display:none;">
<code><pre>
</pre></code>
</div>
<h3>構文</h3>
<code>
<pre>
new ExpForm ();
new ExpForm (form);</pre>
</code>
<h3>引数</h3>
<h4>form</h4>
<p>フォーム要素を指定します。</p>
<h3>説明</h3>
<ul>
<li>引数を与えない場合、ドキュメント上の最初のフォームが対象となります。
<li>フォームの要素で name 属性が無いものは対象外とします
<li>フォームの要素で type 属性が 'submit','reset','button', 'image', 'fieldset', 'file' は対象外とします
</ul>
<h3>インスタンス</h3>
<h4>ExpForm.prototype.reset ()</h4>
<p>form 要素の値をリセットします</p>
<ul>
<li>hidden 属性は、ExpForm を宣言した時の状態を保存しその値を代入します
</ul>
<h4>ExpForm.prototype.get ()</h4>
<p>form 要素の値を object 型にして返します</p>
<ul>
<li>type 属性が 'checkbox', 'select-multiple' は選択状態の要素がなくても空の配列を返します
<li>name 属性が複数あると配列にして返します
<li>type 属性が 'checkbox', 'radio' の選択状態が全くない場合は null を返します
</ul>
<h4>ExpForm.prototype.set (object)</h4>
<p>object 型を走査して form の要素に値を設定します</p>
<ul>
<li>name 属性が同じで複数ある場合は type 属性を以下の順でソートしてから設定します<br>
<em>select-multiple -> checkbox -> select-one -> radio -> その他</em>
<li>type 属性が 'select-one', 'radio' の要素に、配列から複数の値を設定しようとした場合、<br>
複数の選択項目の最後にマッチした value 値の要素を選択状態にします
<li>type 属性が以下のもので選択条件にマッチする要素は、その全てが選択状態となります<br>
また、それ以外の要素には利用されなかった配列の value 値から順に設定されます<br>
<em>"select-multiple", "checkbox", "select-one", "radio"</em>
<li>list 属性があるものは、その option の value 値に含まれるものがあれば、優先して設定されます
</ul>
<h4>ExpForm.prototype.setFromFile (file_name)</h4>
<p>ファイルを読み込んで、要素に値を設定します</p>
<ul>
<li>読み込むファイルは JSON 形式である必要があります。
<li>その後は objec 型に変換し toFromObject () の引数として呼び出します
<li>JSONファイルのキーとなる要素が無い場合は、無視されます
</ul>
<h4>ExpForm.prototype.replaceOptions (object)</h4>
<p>object 型を走査して option 要素を置き換えます</p>
<ul>
<li>SELECT 要素もしくは list 属性で示された要素(datalist) がその対象となります
<li>option 要素は、一旦削除されてから上書きされます。
<li>object の構造は、例として以下のようになります<br>
<code><pre>
{
"name": [
{ "value": "abc" },
{ "value": "def", "text": "DEF" },
{ "value": "ghi", "text": "GHI", "defaultSelewcted": true, "selected": true },
{ "gropu": "japan", "text": "いろは", "value": "イロハ" },
],
"name2": [
{ "value": "abc" },
{ "value": "def", "text": "DEF" }
]
}</pre></code>
</ul>
<h4>ExpForm.prototype.replaceOptionsFromFile (file_name)</h4>
<p>ファイルを読み込んで、option 要素を置き換えます</p>
<ul>
<li>読み込むファイルは JSON 形式である必要があります。
<li>その後は objec 型に変換し replaceOptions () の引数として呼び出します
<li>ファイル名に "./test.php?arg=1" の用にクエリーを付けて呼び出し<br>
PHP 側で$_GET['arg'] などで取得し、ファイルの出力を変える方法もありえます
</ul>
<h3>静的メゾット</h3>
<p>引数に使われる elements はノードリストの他に object 形式でも利用可能です</p>
<code><pre>
let elements = {
'hoge_select-one': [
{group: '春', value: 'かつお', text: '鰹'},
{group: '春', value: 'たこ', text: '蛸'}
],
'hoge_select-multiple': [
{group: '夏', value: 'あじ', text: '鯵'},
{group: '夏', value: 'あゆ', text: '鮎'}
]
};
</pre></code>
<h4>ExpForm.get (elements)</h4>
<p>elements 要素の値を object 型にして返します</p>
<ul>
<li>引数の違いだけで動作は、インスタンスの ExpForm.prototype.get に準じます
</ul>
<h4>ExpForm.set (elements, object)</h4>
<p>object 型を走査して elements の要素に値を設定します</p>
<ul>
<li>引数の違いだけで動作は、インスタンスの ExpForm.prototype.set に準じます
</ul>
<h4>ExpForm.setFromFile (elements, file_name)</h4>
<p>ファイル(JSON)を読み込んで、要素に値を設定します</p>
<ul>
<li>引数の違いだけで動作は、インスタンスの ExpForm.prototype.setFromFile に準じます
</ul>
<h4>ExpForm.replaceOptions (elements, object)</h4>
<p>object 型を走査して option 要素を置き換えます</p>
<ul>
<li>引数の違いだけで動作は、インスタンスの ExpForm.prototype.replaceOptions に準じます
</ul>
<h4>ExpForm.fileLoader (file_name)</h4>
<p>ファイル(JSON)を読み込んで object 型にして返します</p>
<h3 id="TEST">テスト用のフォーム</h3>
<section id="cmp">
<form id="hoge">
<table border="1">
<caption>form#hoge の要素</caption>
<thead>
<tr>
<th>type
<th>element
<tbody>
<tr>
<th>type="file"
<td><input name="hoge_file" type="file" value="sample.txt">
<tr>
<th>type="submit"
<td><input name="hoge_submit" type="submit" value="Submit">
<tr>
<th>type="image"
<td><input name="hoge_image" type="image" value="" alt="ボタンの画像">
<tr>
<th>type="reset"
<td><input name="hoge_reset" type="reset" value="Reset">
<tr>
<th>type="button"
<td><input name="hoge_button" type="button" value="button">
<tbody>
<tr>
<th>type="hidden"
<td onclick="alert(this.firstChild.value);"><input name="hoge_hidden" type="hidden" value="hide">
clickで変数値をアラート
<tr>
<th>type="text"
<td><input name="hoge_text" type="text" value="これはテキスト">
<tr>
<th>type="search"
<td><input name="hoge_search" type="search" value="検索文字">
<tr>
<th>type="tel"
<td><input name="hoge_tel" type="tel" value="0120-12-3456">
<tr>
<th>type="url"
<td><input name="hoge_url" type="url" value="http://raspberry.ne.jp">
<tr>
<th>type="email"
<td><input name="hoge_email" type="email" value="hoge@raspberry.ne.jp">
<tr>
<th>type="password"
<td><input name="hoge_password" type="password" value="1234567890">
<tr>
<th>type="datetime"
<td><input name="hoge_datetime" type="datetime" value="2020-08-19T12:34:56.789">
<tr>
<th>type="date"
<td><input name="hoge_date" type="date" value="2021-01-01">
<tr>
<th>type="month"
<td><input name="hoge_month" type="month" value="2020-02">
<tr>
<th>type="week"
<td><input name="hoge_week" type="week" value="2020-W30">
<tr>
<th>type="time"
<td><input name="hoge_time" type="time" value="12:34:56">
<tr>
<th>type="datetime-local"
<td><input name="hoge_datetime-local" type="datetime-local" value="2020-08-19T12:34:56.789">
<tr>
<th>type="number"
<td><input name="hoge_number" type="number" value="123">
<tr>
<th>type="range"
<td><input name="hoge_range" type="range" value="1000">
<tr>
<th>type="color"
<td><input name="hoge_color" type="color" value="#000000">
<tr>
<th>type="checkbox"
<td><input name="hoge_checkbox" type="checkbox" value="abc">abc
<input name="hoge_checkbox" type="checkbox" value="def">def
<input name="hoge_checkbox" type="checkbox" value="ghi">ghi
<tr>
<th>type="radio"
<td><input name="hoge_radio" type="radio" value="abc">abc
<input name="hoge_radio" type="radio" value="def">def
<input name="hoge_radio" type="radio" value="ghi">ghi
<tr>
<th>type="select-one"
<td><select name="hoge_select-one">
<option value="">選択してください
<option value="abc" selected>abc
<option value="def">def
<option value="ghi">ghi
</select>
<tr>
<th>type="select-multiple"
<td><select name="hoge_select-multiple" multiple>
<option value="">選択してください
<option value="abc" selected>abc
<option value="def">def
<option value="ghi" selected>ghi
</select>
<tr>
<th>type="textarea"
<td><textarea name="hoge_textarea" cols="20" rows="4">Sample text</textarea>
<tbody>
<tr>
<th>name 属性が同じ場合
<td>
<select name="hoge_all" multiple>
<option value="">選択してください
<option value="abc">abc
<option value="def">def
<option value="ghi">ghi
</select><br>
<select name="hoge_all">
<option value="">選択してください
<option value="abc">abc
<option value="def">def
<option value="ghi">ghi
</select><br>
<input name="hoge_all" type="checkbox" value="abc" checked>abc
<input name="hoge_all" type="checkbox" value="def">def
<input name="hoge_all" type="checkbox" value="ghi" checked>ghi<br>
<input name="hoge_all" type="radio" value="abc">abc
<input name="hoge_all" type="radio" value="def" checked>def
<input name="hoge_all" type="radio" value="ghi">ghi<br>
<textarea name="hoge_all" cols="20" rows="4">Sample text</textarea><br>
<input type="text" name="hoge_all" value="123456789">
</table>
</form>
<form id="hoge2">
<table border="1">
<caption>form#hoge2 の要素</caption>
<thead>
<tr>
<th>type
<th>element
<tbody>
<tr>
<th>type="file"
<td><input name="hoge_file" type="file" value="">
<tr>
<th>type="submit"
<td><input name="hoge_submit" type="submit" value="Submit">
<tr>
<th>type="image"
<td><input name="hoge_image" type="image" value="" alt="ボタンの画像">
<tr>
<th>type="reset"
<td><input name="hoge_reset" type="reset" value="Reset">
<tr>
<th>type="button"
<td><input name="hoge_button" type="button" value="button">
<tbody>
<tr>
<th>type="hidden"
<td onclick="alert(this.firstChild.value);"><input name="hoge_hidden" type="hidden" value="">
clickで変数値をアラート
<tr>
<th>type="text"
<td><input name="hoge_text" type="text" value="" list="NO_NULL">
<tr>
<th>type="search"
<td><input name="hoge_search" type="search" value="">
<tr>
<th>type="tel"
<td><input name="hoge_tel" type="tel" value="">
<tr>
<th>type="url"
<td><input name="hoge_url" type="url" value="">
<tr>
<th>type="email"
<td><input name="hoge_email" type="email" value="">
<tr>
<th>type="password"
<td><input name="hoge_password" type="password" value="">
<tr>
<th>type="datetime"
<td><input name="hoge_datetime" type="datetime" value="">
<tr>
<th>type="date"
<td><input name="hoge_date" type="date" value="">
<tr>
<th>type="month"
<td><input name="hoge_month" type="month" value="">
<tr>
<th>type="week"
<td><input name="hoge_week" type="week" value="">
<tr>
<th>type="time"
<td><input name="hoge_time" type="time" value="">
<tr>
<th>type="datetime-local"
<td><input name="hoge_datetime-local" type="datetime-local" value="">
<tr>
<th>type="number"
<td><input name="hoge_number" type="number" value="">
<tr>
<th>type="range"
<td><input name="hoge_range" type="range" value="">
<tr>
<th>type="color"
<td><input name="hoge_color" type="color" value="">
<tr>
<th>type="checkbox"
<td><input name="hoge_checkbox" type="checkbox" value="abc">abc
<input name="hoge_checkbox" type="checkbox" value="def">def
<input name="hoge_checkbox" type="checkbox" value="ghi">ghi
<tr>
<th>type="radio"
<td><input name="hoge_radio" type="radio" value="abc">abc
<input name="hoge_radio" type="radio" value="def">def
<input name="hoge_radio" type="radio" value="ghi">ghi
<tr>
<th>type="select-one"
<td><select name="hoge_select-one">
<option value="">選択してください
<option value="abc">abc
<option value="def">def
<option value="ghi">ghi
</select>
<tr>
<th>type="select-multiple"
<td><select name="hoge_select-multiple" multiple>
<option value="">選択してください
<option value="abc">abc
<option value="def">def
<option value="ghi">ghi
</select>
<tr>
<th>type="textarea"
<td><textarea name="hoge_textarea" cols="20" rows="4"></textarea>
<tbody>
<tr>
<th>name 属性が同じ場合<br>
(並び順に注意)
<td>
<input type="text" name="hoge_all" value="" list="NO"><br>
<textarea name="hoge_all" cols="20" rows="4"></textarea><br>
<input name="hoge_all" type="radio" value="abc">abc
<input name="hoge_all" type="radio" value="def">def
<input name="hoge_all" type="radio" value="ghi">ghi<br>
<input name="hoge_all" type="checkbox" value="abc">abc
<input name="hoge_all" type="checkbox" value="def">def
<input name="hoge_all" type="checkbox" value="ghi">ghi<br>
<select name="hoge_all">
<option value="">選択してください
<option value="abc">abc
<option value="def">def
<option value="ghi">ghi
</select><br>
<select name="hoge_all" multiple>
<option value="">選択してください
<option value="abc">abc
<option value="def">def
<option value="ghi">ghi
</select><br>
</table>
<datalist id="NO">
<option value="123">
<option value="123456789">
<option value="abcdefg">
</datalist>
</form>
</section>
<h3>使用例</h3>
<h4>例:フォームから他のフォームにコピーする</h4>
<code><pre>
let
hoge = new ExpForm (document.querySelector ('form#hoge')),
hoge2 = new ExpForm (document.querySelector ('form#hoge2')),
hoge_obj = hoge.get ();
hoge2.set (hoge_obj);
</pre></code>
<p>
<input type="button" value="実行する" onclick="
let
hoge = new ExpForm (document.querySelector ('form#hoge')),
hoge2 = new ExpForm (document.querySelector ('form#hoge2')),
hoge_obj = hoge.get ();
hoge2.set (hoge_obj);
">
</p>
<h4>例2:フォームのコピー</h4>
<code><pre>
let
hoge = document.querySelector ('form#hoge'),
hoge2 = document.querySelector ('form#hoge2');
ExpForm.set (hoge2.elements, ExpForm.get (hoge.elements));
</pre></code>
<p>
<input type="button" value="実行する" onclick="
let
hoge = document.querySelector ('form#hoge'),
hoge2 = document.querySelector ('form#hoge2');
ExpForm.set (hoge2.elements, ExpForm.get (hoge.elements));
">
</p>
<h4>例:フォームの指定されたname属性の値を取得コピーする</h4>
<code><pre>
let
hoge = new ExpForm (document.querySelector ('form#hoge')),
hoge2 = new ExpForm (document.querySelector ('form#hoge2'));
let
rec = hoge.get ('hoge_text', 'hoge_hidden', 'hoge_all');
hoge2.set (rec);
</pre></code>
<p>
<input type="button" value="実行する" onclick="
let
hoge = new ExpForm (document.querySelector ('form#hoge')),
hoge2 = new ExpForm (document.querySelector ('form#hoge2'));
let
rec = hoge.get ('hoge_text', 'hoge_hidden', 'hoge_all');
hoge2.set (rec);
">
</p>
<h4>例:ファイル(JSON)から読み込んでフォームに値を設定する</h4>
<code><pre>
let exform = new ExpForm (document.forms[0]);
exform.setFromFile ('./test.json');
</pre></code>
<h4>例:SELECT 要素の option の値を書き換える</h4>
<code><pre>
let selects = {
'hoge_select-one': [
{value: '', text: '選択してください', selected: true},
{group: '春', value: 'うめ', text: '梅'},
{group: '春', value: 'さくら', text: '桜'},
{group: '夏', value: 'あさがお', text: '朝顔'},
{group: '夏', value: 'ひまわり', text: '向日葵'},
{group: '秋', value: 'すすき', text: '芒'},
{group: '冬', value: 'すいせん', text: '水仙'},
{value: 'ざっそう', text: '雑草'}
],
'hoge_select-multiple': [
{value: '', text: '選択してください'},
{group: '春', value: 'うめ', text: '梅', selected: true},
{group: '春', value: 'さくら', text: '桜', selected: true},
{group: '夏', value: 'あさがお', text: '朝顔'},
{group: '夏', value: 'ひまわり', text: '向日葵'},
{group: '秋', value: 'すすき', text: '芒'},
{group: '冬', value: 'すいせん', text: '水仙'},
{value: 'ざっそう', text: '雑草'}
]
};
ExpForm. replaceOptions (document.querySelector ('form#hoge2').elements, selects);
</pre></code>
<p>
<input type="button" value="実行する" onclick="
let selects = {
'hoge_select-one': [
{value: '', text: '選択してください', selected: true},
{group: '春', value: 'うめ', text: '梅'},
{group: '春', value: 'さくら', text: '桜'},
{group: '夏', value: 'あさがお', text: '朝顔'},
{group: '夏', value: 'ひまわり', text: '向日葵'},
{group: '秋', value: 'すすき', text: '芒'},
{group: '冬', value: 'すいせん', text: '水仙'},
{value: 'ざっそう', text: '雑草'}
],
'hoge_select-multiple': [
{value: '', text: '選択してください'},
{group: '春', value: 'うめ', text: '梅', selected: true},
{group: '春', value: 'さくら', text: '桜', selected: true},
{group: '夏', value: 'あさがお', text: '朝顔'},
{group: '夏', value: 'ひまわり', text: '向日葵'},
{group: '秋', value: 'すすき', text: '芒'},
{group: '冬', value: 'すいせん', text: '水仙'},
{value: 'ざっそう', text: '雑草'}
]
};
ExpForm. replaceOptions (document.querySelector ('form#hoge2').elements, selects);
">
<h4>例:異なる FORM の中の 複数の SELECT 要素の option の値を書き換える</h4>
<code><pre>
let
es = {
"hoge_select-one": document.querySelector ('#hoge select[name="hoge_select-one"]'),
"hoge_select-multiple": document.querySelector ('#hoge2 select[name="hoge_select-multiple"]'),
};
let selects = {
'hoge_select-one': [
{group: '春', value: 'かつお', text: '鰹'},
{group: '春', value: 'たこ', text: '蛸'}
],
'hoge_select-multiple': [
{group: '夏', value: 'あじ', text: '鯵'},
{group: '夏', value: 'あゆ', text: '鮎'}
]
};
ExpForm.replaceOptions (es, selects);
</pre></code>
<p>
<input type="button" value="実行する" onclick="
let
es = {
'hoge_select-one': document.querySelector ('#hoge select[name=hoge_select-one]'),
'hoge_select-multiple': document.querySelector ('#hoge2 select[name=hoge_select-multiple]'),
};
let selects = {
'hoge_select-one': [
{group: '春', value: 'かつお', text: '鰹'},
{group: '春', value: 'たこ', text: '蛸'}
],
'hoge_select-multiple': [
{group: '夏', value: 'あじ', text: '鯵'},
{group: '夏', value: 'あゆ', text: '鮎'}
]
};
ExpForm.replaceOptions (es, selects);
"></p>
<script>
{
const
PRIORITY_ELEMENTS = {
'select-multiple': 10,
'checkbox': 9,
'select-one': 8,
'radio': 7,
},
priority = ({type:a}, {type:b}) =>
((PRIORITY_ELEMENTS[a] || 0) < (PRIORITY_ELEMENTS[b] || 0)),
pushHiddenValue = (form) =>
new Map (
Array.from (form.elements)
.filter (e => 'hidden' === e.type)
.map (e => [e, e.defaultValue])
),
popHiddenValue = obj =>
Array.from (obj.form.elements)
.filter (e => 'hidden' === e.type)
.forEach (e => e.value = obj.hidden.get (e)),
removeAllChild = p => {
while (p.hasChildNodes ())
p.removeChild (p.firstChild);
},
fileLoader = (file) => {
if (! XMLHttpRequest)
throw new Error ('利用できません');
let
req = new XMLHttpRequest (),
res = null;
req.open ('GET', file, false);
req.send (null);
res = req.responseText.replace(/(\u2028|\u2029|\s|\r\n|\r|\n)/gm,'');
try {
return JSON.parse (res);
} catch (err) {
console.log (res);
throw new Error ('JSONに変換できませんでした');
}
},
setValue = (es = null, obj = { }) => {
if (null === es)
throw new Error ('FORMの中の要素がありません');
for (let name of Object.keys (obj)) {
let target = es[name];
if (! target)
continue;
if (target.nodeType === Node.ELEMENT_NODE)
target = [target];
let values = obj[name];
if (! Array.isArray (values))
values = [values];
let used = Array.of.apply ([ ], values);
target = Array.from (target).sort (priority);
EScanning:
for (let e of target) {
switch (e.type) {
case 'submit' : case 'reset' : case 'button' :
case 'image' : case 'fieldset': case 'file' :
continue; break;
case 'select-one' :
case 'select-multiple' : {
let op = e.options;
if (op.length)
for (let o of e.options) {
if (values.includes (o.value)) {
o.selected = true;
let idx = used.indexOf (o.value);
if (-1 < idx)
used.splice (idx, 1);
}
}
}
break;
case 'radio' :
case 'checkbox' :
let checked = e.checked = values.includes (e.value);
if (checked) {
let idx = used.indexOf (e.value);
if (-1 < idx)
used.splice (idx, 1);
}
break;
default:
if (e.hasAttribute ('list')) {
let op = e.list ? e.list.options: null;
if (op) {
for (let v of Array.from (op, o => o.value)) {
let x = used.indexOf (String (v));
if (-1 < x) {
e.value = used.splice (x, 1);
continue EScanning;
}
}
}
}
e.value = used.shift () || '';
break;
}
}
}
},
getValue = (es) => {
let
result = { };
for (let e of es) {
let type = e.type, name;
switch (type) {
case 'submit' : case 'reset' : case 'button' :
case 'image' : case 'fieldset': case 'file' :
continue; break;
default :
name = e.name;
if (! name) continue;
}
let value = result[name], v;
if ('undefined' === typeof value)
result[name] = value = null;
switch (type) {
case 'select-multiple' :
v = [];
if (-1 < e.selectedIndex)
for (let o of e.options)
if (o.selected)
v.push (o.value);
break;
case 'select-one' :
if (0 > e.selectedIndex) continue;
v = e.options[e.selectedIndex].value;
break;
case 'checkbox' :
v = e.checked ? [e.value]: [ ];
break;
case 'radio' :
if (! e.checked) continue;
default :
v = e.value;
}
result[name] =
(Array.isArray (value))
? value.concat (v)
: (null !== value)
? [value, v]
: v;
}
return result;
},
replaceOptions = (elements, obj) => {
Object.keys (obj).forEach (name => {
let es = elements[name];
es = es
? es.nodeType === Node.ELEMENT_NODE
? [es]
: Array.from (es)
: [ ];
for (let e of es) {
let rec = obj[name], dl;
if ('SELECT' === e.tagName) {
let
m = null,
current = null,
obj;
removeAllChild (e);
while (obj = rec.shift ()) {
let
label = obj.group || null,
option = new Option (
('undefined' !== typeof obj.text ? obj.text: obj.value),
obj.value,
!! obj.defaultSelected,
!! obj.selected
);
if (m !== label) {
let optgroup = e.ownerDocument.createElement ('optgroup');
optgroup.setAttribute ('label', label);
current = label ? e.appendChild (optgroup): null;
}
(current || e).appendChild (option);
m = label;
}
} else {
if (e.hasAttribute ('list')) {
if (dl = e.list) {
removeAllChild (dl);
for (let r of rec) {
dl.appendChild (new Option (r.text, r.value));
}
}
}
}
}
})
},
O = (a,b) => Array.isArray (b) ? b.reduce (O, a): (a.push (b), a),
U = (a,b) => a.has (b) ? a: a.set (b, 1),
S = a => a ? 'string' === typeof a : false,
L = (a,b) => b.nodeType === Node.ELEMENT_NODE ? (a.push (b), a): a.concat ([...b]),
N = a => !!a,
pickup = function (elements, ...args) {
return [...
[...args
.reduce (O, [ ])
.reduce (U, new Map)
.keys ()
].filter (S)
.map (n => elements[n])
.filter (N)
.reduce (L, [])
.reduce (U, new Map)
.keys()
];
};
class ExpForm {
constructor (form = document.form[0]) {
if (1 > arguments.length)
throw new Erorr ('引数が足りません');
if ('FORM' !== form.tagName)
throw new Erorr ('FORMではありません');
this.form = form;
this.hidden = pushHiddenValue (form);
}
reset () {
this.form.reset ();
popHiddenValue (this);
return this;
}
set (obj = { }) {
setValue (this.form.elements, obj);
return this;
}
get (...args) {
let
es = this.form.elements,
elements = 0 === args.length
? es
: pickup (es, args);
return getValue (elements);
}
setFromFile (file) {
if (1 > arguments.length)
throw new Error ('ファイル名が指定されていません');
this.set (fileLoader (file));
return this;
}
replaceOptions (obj) {
if (1 > arguments.length)
throw new Error ('引数が足りません');
replaceOptions (this.form.elements, obj);
return this;
}
replaceOptionsFromFile (file) {
if (1 > arguments.length)
throw new Error ('ファイル名が指定されていません');
let json = fileLoader (file);
return this.replaceOptions (json);
}
static set (elements, obj) {
setValue (elements, obj);
}
static setFromFile (elements, file) {
setValue (elements, fileLoader (file));
}
static get (es, ...args) {
let
elements = 0 === args.length
? es
: pickup (es, args);
return getValue (es);
}
static replaceOptions (elements, obj) {
replaceOptions (elements, obj);
}
static replaceOptionsFromFile (elements, file) {
let json = fileLoader (file);
replaceOptions (elements, json);
}
static fileLoader (file) {
return fileLoader (file);
}
static pickup (es, args) {
return pickup (es, args);
}
}
this.ExpForm = ExpForm;
}
</script>
<script>
document.querySelector ('#EXPFORM code pre').textContent =
document.querySelector ('script').textContent;
</script>