nadesiko3
Version:
Japanese Programming Language
679 lines (678 loc) • 25.3 kB
JavaScript
export default {
// @DOM部品操作
'DOM親要素': { type: 'const', value: '' }, // @DOMおやようそ
'DOM部品個数': { type: 'const', value: 0 }, // @DOMせいせいこすう
'DOM部品オプション': { type: 'const', value: { '自動改行': false, 'テーブルヘッダ': true, 'テーブル背景色': ['#AA4040', '#ffffff', '#fff0f0'], 'テーブル数値右寄せ': true } }, // @DOMぶひんおぷしょん
'DOM親要素設定': {
type: 'func',
josi: [['に', 'へ']],
pure: true,
fn: function (el, sys) {
if (typeof el === 'string') {
el = document.querySelector(el) || document.getElementById(el);
}
sys.__setSysVar('DOM親要素', el);
sys.__addPropMethod(el);
return el;
}
},
'DOM親部品設定': {
type: 'func',
josi: [['に', 'へ']],
pure: true,
fn: function (el, sys) {
return sys.__exec('DOM親要素設定', [el, sys]);
}
},
'DOMスキン': { type: 'const', value: '' }, // @DOMすきん
'DOMスキン辞書': { type: 'const', value: {} }, // @DOMすきんじしょ
'DOMスキン設定': {
type: 'func',
josi: [['を', 'に', 'の']],
pure: true,
fn: function (skin, sys) {
sys.__setSysVar('DOMスキン', skin);
},
return_none: true
},
'DOM部品作成': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (elm, sys) {
const parent = sys.__getSysVar('DOM親要素');
const btn = (typeof (elm) === 'string') ? document.createElement(elm) : elm;
btn.id = 'nadesi-dom-' + sys.__getSysVar('DOM部品個数');
sys.__addPropMethod(btn);
// スキン適用
const func = sys.__getSysVar('DOMスキン辞書')[sys.__getSysVar('DOMスキン')];
if (typeof (func) === 'function') {
func(elm, btn, sys);
}
// DOM追加
parent.appendChild(btn);
sys.__setSysVar('DOM部品個数', sys.__getSysVar('DOM部品個数', 0) + 1);
// オプションを適用
const opt = sys.__getSysVar('DOM部品オプション');
if (opt['自動改行']) {
parent.appendChild(document.createElement('br'));
}
// 「その」を設定
sys.__setSysVar('そ', btn);
return btn;
}
},
'DOM部品削除': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (elm) {
if (typeof elm === 'string') {
elm = document.querySelector(elm);
}
if (elm) {
elm.parentNode.removeChild(elm);
}
},
return_none: true
},
'ボタン作成': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (label, sys) {
const btn = sys.__exec('DOM部品作成', ['button', sys]);
btn.innerHTML = label;
return btn;
}
},
'エディタ作成': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (text, sys) {
const inp = sys.__exec('DOM部品作成', ['input', sys]);
inp.type = 'text';
inp.value = text;
return inp;
}
},
'テキストエリア作成': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (text, sys) {
const te = sys.__exec('DOM部品作成', ['textarea', sys]);
te.value = text;
return te;
}
},
'ラベル作成': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (text, sys) {
const lbl = sys.__exec('DOM部品作成', ['span', sys]);
lbl.innerHTML = text;
return lbl;
}
},
'キャンバス作成': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (size, sys) {
const cv = sys.__exec('DOM部品作成', ['canvas', sys]);
cv.width = size[0];
cv.height = size[1];
cv.style.width = size[0];
cv.style.height = size[1];
// 描画中キャンバスを移動する
sys.__exec('描画開始', [cv, sys]);
return cv;
}
},
'画像作成': {
type: 'func',
josi: [['の', 'から']],
pure: true,
fn: function (url, sys) {
const img = sys.__exec('DOM部品作成', ['img', sys]);
img.src = url;
return img;
}
},
'改行作成': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
const br = sys.__exec('DOM部品作成', ['br', sys]);
return br;
}
},
'チェックボックス作成': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (text, sys) {
// チェックボックスは、<span><input><label></span>で成り立つように構築
const span = document.createElement('span');
const inp = document.createElement('input');
inp.type = 'checkbox';
inp.id = 'nadesi-dom-' + sys.__getSysVar('DOM部品個数', 0);
sys.__setSysVar('DOM部品個数', sys.__getSysVar('DOM部品個数', 0) + 1);
const label = document.createElement('label');
label.innerHTML = text;
label.htmlFor = inp.id;
span.appendChild(inp);
span.appendChild(label);
// 親部品に追加
sys.__exec('DOM部品作成', [span, sys]);
return inp;
}
},
'セレクトボックス作成': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (options, sys) {
const dom = document.createElement('select');
for (let i = 0; i < options.length; i++) {
const item = document.createElement('option');
item.value = options[i];
item.appendChild(document.createTextNode(options[i]));
dom.appendChild(item);
}
// 親部品に追加
sys.__exec('DOM部品作成', [dom, sys]);
return dom;
}
},
'セレクトボックスアイテム設定': {
type: 'func',
josi: [['を'], ['へ', 'に']],
pure: true,
fn: function (options, dom) {
if (typeof dom === 'string') {
dom = document.querySelector(dom);
}
// 既存のoptionsをクリア
dom.options.length = 0;
// アイテムを追加
for (let i = 0; i < options.length; i++) {
const item = document.createElement('option');
item.value = options[i];
item.appendChild(document.createTextNode(options[i]));
dom.appendChild(item);
}
},
return_none: true
},
'色選択ボックス作成': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
const inp = sys.__exec('DOM部品作成', ['input', sys]);
inp.type = 'color';
return inp;
}
},
'日付選択ボックス作成': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
const inp = sys.__exec('DOM部品作成', ['input', sys]);
inp.type = 'date';
return inp;
}
},
'パスワード入力エディタ作成': {
type: 'func',
josi: [['の', 'で']],
pure: true,
fn: function (s, sys) {
const inp = sys.__exec('DOM部品作成', ['input', sys]);
inp.type = 'password';
inp.value = s;
return inp;
}
},
'値指定バー作成': {
type: 'func',
josi: [['の', 'で']],
pure: true,
fn: function (range, sys) {
if (!(range instanceof Array) || range.length < 2) {
range = [0, 100, 50];
}
if (range.length <= 2) { // 3つ目を省略したとき
range.push(Math.floor((range[1] - range[0]) / 2));
}
const inp = sys.__exec('DOM部品作成', ['input', sys]);
inp.type = 'range';
inp.min = range[0];
inp.max = range[1];
inp.value = range[2];
return inp;
}
},
'送信ボタン作成': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (label, sys) {
const inp = sys.__exec('DOM部品作成', ['input', sys]);
inp.type = 'submit';
inp.value = label;
return inp;
}
},
'フォーム作成': {
type: 'func',
josi: [['で', 'の'], ['を']],
pure: true,
fn: function (obj, s, sys) {
const frm = sys.__exec('DOM部品作成', ['form', sys]);
// 可能ならformにobjの値を移し替える
if (obj instanceof Object) {
for (const key in obj) {
if (frm[key]) {
frm[key] = obj[key];
}
}
}
// 入力項目をtableで作る
const table = document.createElement('table');
// 入力項目がstringの場合、改行で分割
let rows;
if (typeof s === 'string') {
rows = s.split('\n');
}
else {
rows = s;
}
// 入力項目に合わせて行を追加
for (const rowIndex in rows) {
const row = rows[rowIndex];
let cols;
if (typeof row === 'string') {
cols = row.split('=');
}
else {
cols = row;
}
while (cols.length < 4) {
cols.push('');
}
const key = cols[0];
const val = cols[1];
const opt1 = cols[2];
const opt2 = cols[3];
let isHidden = false;
if (key === '' && val === '') {
continue;
} // 空行は無視
// key
const th = document.createElement('th');
const lbl = document.createElement('label');
lbl.innerHTML = sys.__tohtmlQ(key);
th.appendChild(lbl);
// val
const td = document.createElement('td');
if (val.substring(0, 2) === '?(') {
// select box
const it = val.substring(2) + ')';
const ita = it.split(')');
const its = ita[0];
const def = ita[1];
const items = its.split('|');
const select = document.createElement('select');
select.name = key;
for (const it of items) {
const option = document.createElement('option');
option.value = it;
option.text = it;
select.appendChild(option);
}
const idx = items.indexOf(def);
if (idx >= 0) {
select.selectedIndex = idx;
}
td.appendChild(select);
}
else {
// input element
const inp = document.createElement('input');
td.appendChild(inp);
const lbl2 = document.createElement('label');
td.appendChild(lbl2);
inp.id = 'nako3form_' + key;
lbl.htmlFor = inp.id;
// check type v3.6.37
if (val === '?text') {
inp.type = 'text';
inp.value = opt1;
inp.placeholder = opt2;
inp.name = key;
}
else if (val === '?password') {
inp.type = 'password';
inp.value = opt1;
inp.placeholder = opt2;
inp.name = key;
}
else if (val === '?number') {
inp.type = 'number';
inp.value = opt1;
inp.placeholder = opt2;
inp.name = key;
}
else if (val === '?email') {
inp.type = 'email';
inp.value = opt1;
inp.placeholder = opt2;
inp.name = key;
}
else if (val === '?tel') {
inp.type = 'tel';
inp.value = opt1;
inp.placeholder = opt2;
inp.name = key;
}
else if (val === '?file') {
inp.type = 'file';
inp.name = key;
}
else if (val === '?date') {
inp.type = 'date';
inp.value = opt1.replace(/\//g, '-');
inp.name = key;
}
else if (val === '?month') {
inp.type = 'month';
inp.value = opt1.replace(/\//g, '-');
inp.name = key;
}
else if (val === '?time') {
inp.type = 'time';
inp.value = opt1;
inp.name = key;
}
else if (val === '?color') {
inp.type = 'color';
inp.value = opt1;
inp.name = key;
}
else if (val === '?hidden') {
inp.type = 'hidden';
inp.value = opt1;
inp.name = key;
isHidden = true;
frm.appendChild(inp);
}
else if (val === '?checkbox') {
inp.type = 'checkbox';
inp.value = opt1;
inp.name = key;
lbl2.innerHTML = ' ' + sys.__tohtmlQ(opt2);
lbl2.htmlFor = inp.id;
}
else if (val === '?送信' || val === '?submit') { // v3.2.33での拡張
inp.type = 'submit';
inp.value = val.substring(1);
if (key !== '') {
inp.name = key;
}
}
else if (val.substring(0, 3) === '?c#') {
inp.type = 'color';
inp.value = val.substring(2);
inp.name = key;
}
else {
inp.type = 'text';
inp.value = val;
inp.name = key;
}
}
if (isHidden) {
continue;
}
const tr = document.createElement('tr');
tr.appendChild(th);
tr.appendChild(td);
table.appendChild(tr);
}
frm.appendChild(table);
return frm;
}
},
'フォーム入力一括取得': {
type: 'func',
josi: [['の', 'から']],
pure: true,
fn: function (dom) {
if (typeof (dom) === 'string') {
dom = document.querySelector(dom);
}
const res = {};
const getChildren = (pa) => {
if (!pa || !pa.childNodes) {
return;
}
for (let i = 0; i < pa.childNodes.length; i++) {
const el = pa.childNodes[i];
if (!el.tagName) {
return;
}
const tag = el.tagName.toLowerCase();
if (tag === 'input') {
if (el.type === 'checkbox') {
res[el.name] = el.checked ? el.value : '';
continue;
}
res[el.name] = el.value;
continue;
}
else if (tag === 'textarea') {
res[el.name] = el.value;
}
else if (tag === 'select') {
if (el.selectedIndex >= 0) {
res[el.name] = el.options[el.selectedIndex].value;
}
else {
res[el.name] = '';
}
}
getChildren(el);
}
};
getChildren(dom);
return res;
}
},
'テーブル作成': {
type: 'func',
josi: [['の', 'から']],
pure: true,
fn: function (aa, sys) {
const table = sys.__exec('DOM部品作成', ['table', sys]);
return sys.__exec('テーブル更新', [table, aa, sys]);
}
},
'ヘッダ有テーブル作成': {
type: 'func',
josi: [['の', 'から']],
pure: true,
fn: function (aa, sys) {
const domOption = sys.__getSysVar('DOM部品オプション');
const tmpTableHeader = domOption['テーブルヘッダ'];
domOption['テーブルヘッダ'] = true;
const obj = sys.__exec('テーブル作成', [aa, sys]);
domOption['テーブルヘッダ'] = tmpTableHeader;
return obj;
}
},
'ヘッダ無テーブル作成': {
type: 'func',
josi: [['の', 'から']],
pure: true,
fn: function (aa, sys) {
const domOption = sys.__getSysVar('DOM部品オプション');
const tmpTableHeader = domOption['テーブルヘッダ'];
domOption['テーブルヘッダ'] = false;
const obj = sys.__exec('テーブル作成', [aa, sys]);
domOption['テーブルヘッダ'] = tmpTableHeader;
return obj;
}
},
'テーブル更新': {
type: 'func',
josi: [['を'], ['に', 'へ']],
pure: true,
fn: function (tbl, aa, sys) {
// 既存のテーブルを取得
if (typeof tbl === 'string') {
tbl = sys.__query(tbl, 'テーブル更新', false);
}
tbl.innerHTML = ''; // 初期化
// テーブルに差し込むデータを確認 - 文字列ならarray[array[str]]に変換
if (typeof aa === 'string') {
aa = sys.__exec('CSV取得', [aa, sys]);
}
const table = tbl;
// テーブル作成/テーブル更新の設定を読み取る
const domOption = sys.__getSysVar('DOM部品オプション');
// 背景色は複製して使う
const bgColor = JSON.parse(JSON.stringify(domOption['テーブル背景色']));
for (let i = 0; i < 3; i++) {
bgColor.push('');
}
const bgHead = bgColor.shift() || '';
let hasHeader = domOption['テーブルヘッダ'];
let isNumRight = domOption['テーブル数値右寄せ'];
// 既存のテーブルに設定があれば読み取る
if (table.dataset.nakoOptions !== undefined) {
const nakoOptions = JSON.parse(table.dataset.nakoOptions);
hasHeader = nakoOptions.hasHeader;
isNumRight = nakoOptions.isNumRight;
}
// 設定をDOMに保存
table.dataset.nakoOptions = JSON.stringify({
hasHeader,
isNumRight
});
// テーブルにデータを追加していく
for (let i = 0; i < aa.length; i++) {
const rowNo = i;
const row = aa[rowNo];
const tr = document.createElement('tr');
// 色指定
if (bgHead !== '') {
const no = hasHeader ? rowNo : rowNo + 1;
tr.style.backgroundColor = no === 0 ? bgHead : bgColor[no % 2];
tr.style.color = no === 0 ? 'white' : 'black';
}
for (let col of row) {
col = '' + col;
const td = document.createElement(rowNo === 0 && hasHeader ? 'th' : 'td');
td.innerHTML = sys.__tohtml(col);
if (isNumRight && col.match(/^(\+|-)?\d+(\.\d+)?$/)) {
// number?
td.style.textAlign = 'right';
}
tr.appendChild(td);
}
table.appendChild(tr);
}
return table;
}
},
'テーブルセル変更': {
type: 'func',
josi: [['の'], ['を'], ['に', 'へ']],
pure: true,
fn: function (t, cell, v, sys) {
if (typeof (t) === 'string') {
t = document.querySelector(t);
}
if (typeof (cell) === 'string') {
cell = cell.split(',');
}
if (cell.length !== 2) {
throw new Error('『テーブルセル変更』の引数「を」は[行,列]の形式で指定してください。');
}
const row = cell[0];
const col = cell[1];
if (!(v instanceof Array)) {
v = [[v]];
}
// オプションを取得
const domOption = sys.__getSysVar('DOM部品オプション');
const bgColor = JSON.parse(JSON.stringify(domOption['テーブル背景色'])); // 複製して使う
const isNumRight = domOption['テーブル数値右寄せ'];
while (bgColor.length < 3) { // オプションが壊れていた時のための補完
bgColor.push('white');
}
// 複数の範囲を一気に変更
for (let y = 0; y < v.length; y++) {
const vRow = v[y];
for (let x = 0; x < vRow.length; x++) {
const yy = row + y;
let domTR = t.childNodes[yy];
while (!domTR) {
const newTR = document.createElement('tr');
t.appendChild(newTR);
domTR = t.childNodes[yy];
domTR.style.backgroundColor = bgColor[yy % 2 + 1];
}
let td = domTR.childNodes[col + x];
while (!td) {
const newTD = document.createElement('td');
domTR.appendChild(newTD);
td = domTR.childNodes[col + x];
}
const v = String(vRow[x]);
td.innerHTML = sys.__tohtml(v);
if (isNumRight && v.match(/^(\+|-)?\d+(\.\d+)?$/)) { // number?
td.style.textAlign = 'right';
}
}
}
},
return_none: true
},
'マーメイド作成': {
type: 'func',
josi: [['の']],
pure: true,
asyncFn: true,
fn: async function (src, sys) {
const div = sys.__exec('DOM部品作成', ['div', sys]);
div.classList.add('mermaid');
div.innerHTML = src;
// ライブラリを読み込む
const win = sys.__getSysVar('WINDOW');
if (typeof win.mermaid === 'undefined') {
console.log('try to load mermaid');
await sys.__loadScript('https://cdn.jsdelivr.net/npm/mermaid@10.5.0/dist/mermaid.min.js');
console.log('mermaid.jsを読み込みました');
}
await win.mermaid.run();
return div;
}
},
'ビデオ作成': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
const video = sys.__exec('DOM部品作成', ['video', sys]);
return video;
}
}
};