danoniplus 40.1.0 → 40.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/danoni_main.js CHANGED
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2025/03/02
7
+ * Revised : 2025/03/08
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 40.1.0`;
12
- const g_revisedDate = `2025/03/02`;
11
+ const g_version = `Ver 40.3.0`;
12
+ const g_revisedDate = `2025/03/08`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -475,19 +475,20 @@ const getIndent = (_level) => ' '.repeat(_level * 4);
475
475
  * ストレージ情報の取得
476
476
  * @param {string} _name g_storageFuncの実行キー名
477
477
  * @param {string} _key g_storageFuncの実行キーの引数
478
+ * @param {boolean} [_colorFmt=true]
478
479
  * @returns {string}
479
480
  */
480
- const viewKeyStorage = (_name, _key = ``) => {
481
+ const viewKeyStorage = (_name, _key = ``, _colorFmt = true) => {
481
482
 
482
483
  // キャッシュ設定
483
484
  if (!viewKeyStorage.cache) {
484
485
  viewKeyStorage.cache = new Map();
485
486
  }
486
- const cacheKey = _key + _name;
487
+ const cacheKey = _key + _name + String(_colorFmt);
487
488
  if (viewKeyStorage.cache.has(cacheKey)) {
488
489
  return viewKeyStorage.cache.get(cacheKey);
489
490
  }
490
- const result = formatObject(g_storageFunc.get(_name)?.(_key) || setVal(_name, ``, C_TYP_CALC));
491
+ const result = formatObject(g_storageFunc.get(_name)?.(_key) || setVal(_name, ``, C_TYP_CALC), 0, { colorFmt: _colorFmt });
491
492
  viewKeyStorage.cache.set(cacheKey, result);
492
493
  return result;
493
494
  }
@@ -496,44 +497,53 @@ const viewKeyStorage = (_name, _key = ``) => {
496
497
  * オブジェクトのネスト表示処理
497
498
  * @param {Object} _obj
498
499
  * @param {Number} _indent
499
- * @param {WeakSet} [seen=new WeakSet()]
500
- * @param {boolean} [colorFmt=true]
501
- * @param {string} [key='']
500
+ * @param {boolean} [colorFmt=true] フォーマット加工フラグ
501
+ * @param {string} [rootKey=''] オブジェクトの最上位プロパティ名
502
502
  * @param {Object} [_parent=null]
503
503
  * @returns {string}
504
504
  */
505
- const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true, key = `` } = {}, _parent = null) => {
505
+ const formatObject = (_obj, _indent = 0, { colorFmt = true, rootKey = `` } = {}) => {
506
506
  if (_obj === null || typeof _obj !== 'object') {
507
507
  return JSON.stringify(_obj);
508
508
  }
509
- if (seen.has(_obj)) {
510
- return '[Circular]';
511
- }
512
- seen.add(_obj);
513
509
  const baseIndent = getIndent(_indent);
514
510
  const nestedIndent = getIndent(_indent + 1);
515
511
 
516
- // カラーコード、対応キーの色付け処理
517
- const colorCodePattern = /(#|0x)(?:[A-Fa-f0-9]{6}(?:[A-Fa-f0-9]{2})?|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{3})/g;
518
- const formatValue = (_value, _parent) => {
512
+ /**
513
+ * データの装飾処理
514
+ * @param {string|boolean|number|Object} _value
515
+ * @param {string} _rootKey
516
+ * @returns {string}
517
+ */
518
+ const formatValue = (_value, _rootKey) => {
519
519
  if (colorFmt) {
520
- if (typeof _value === 'string') {
521
- _value = escapeHtml(_value);
520
+ if (typeof _value === C_TYP_STRING) {
521
+
522
+ // カラーコードの色付け処理
523
+ _value = escapeHtml(_value).replaceAll(`\n`, `<br>`);
524
+ const colorCodePattern = /(#|0x)(?:[A-Fa-f0-9]{6}(?:[A-Fa-f0-9]{2})?|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{3})/g;
522
525
  if (colorCodePattern.test(_value)) {
523
526
  return _value.replace(colorCodePattern, (match) =>
524
527
  `<span style="color:${match.replace(`0x`, `#`)}">◆</span>${match.replace(`0x`, `#`)}`);
525
528
  }
526
- }
527
- if (Array.isArray(_value)) {
528
- let formattedArray = _value.map(item => formatValue(item, _value));
529
- if (key.startsWith(`keyCtrl`)) {
530
- formattedArray = formattedArray.filter(item => item !== `0`)
531
- .map(item => g_kCd[item] ? `${item}|<span style="color:#ffff66">${g_kCd[item]}</span>` : item);
529
+ } else if (typeof _value === C_TYP_BOOLEAN) {
530
+
531
+ // boolean値の色付け処理
532
+ return (_value ? `<span style="color:#66ff66">&#x2714; true</span>` :
533
+ `<span style="color:#ff9999">&#x274c; false</span>`);
534
+
535
+ } else if (typeof _value === C_TYP_NUMBER) {
536
+
537
+ if (_rootKey.startsWith(`scrollDir`)) {
538
+ // scrollDirXのスクロール方向表示処理
539
+ return _value === 1 ? `1|<span style="color:#ff9999">↑</span>` : `-1|<span style="color:#66ff66">↓</span>`;
540
+
541
+ } else if (_rootKey.startsWith(`keyCtrl`) && !_rootKey.startsWith(`keyCtrlPtn`)) {
542
+ // keyCtrlXの対応キー表示処理
543
+ return (g_kCd[_value] && _value !== 0) ? `${_value}|<span style="color:#ffff66">${g_kCd[_value]}</span>` : `----`;
532
544
  }
533
- return `[${formattedArray.join(`, `)}]`;
534
- }
535
- if (typeof _value === 'object' && _value !== null) {
536
- return formatObject(_value, _indent + 1, { seen, colorFmt, key }, _parent);
545
+ } else if (typeof _value === C_TYP_OBJECT && _value !== null) {
546
+ return formatObject(_value, _indent + 1, { colorFmt, rootKey: _rootKey });
537
547
  }
538
548
  }
539
549
  return JSON.stringify(_value);
@@ -547,7 +557,7 @@ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true
547
557
  if (colorFmt && _obj.length > 100) {
548
558
  const filteredArray = _obj.reduce((result, value, index) => {
549
559
  if (hasVal(value)) {
550
- result.push(`${index}: ${formatValue(value, _obj)}`);
560
+ result.push(`${index}: ${formatValue(value, rootKey)}`);
551
561
  }
552
562
  return result;
553
563
  }, []);
@@ -558,11 +568,11 @@ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true
558
568
  .map(value => {
559
569
  const isNestedObject = typeof value === 'object' && value !== null;
560
570
  return isArrayOfArrays
561
- ? `${nestedIndent}${formatValue(value, _obj)}`
571
+ ? `${nestedIndent}${formatValue(value, rootKey)}`
562
572
  : isNestedObject
563
- ? formatObject(value, _indent + 1, { seen, colorFmt }, _obj)
564
- : formatValue(value, _obj)
565
- }).join(isArrayOfArrays ? `,<br>` : `, `);
573
+ ? formatObject(value, _indent + 1, { colorFmt, rootKey })
574
+ : formatValue(value, rootKey)
575
+ }).filter(val => !hasVal(val) || val !== `----`).join(isArrayOfArrays ? `,<br>` : `, `);
566
576
 
567
577
  return `[${isArrayOfArrays ? `<br>` : ``}${formattedArray}${isArrayOfArrays ? `<br>${baseIndent}` : ''}]`;
568
578
  }
@@ -571,12 +581,12 @@ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true
571
581
  const formattedEntries = Object.entries(_obj)
572
582
  .map(([key, value]) => {
573
583
  const isNestedObject = typeof value === 'object' && value !== null;
574
- const seenNew = _parent ? seen : new WeakSet();
584
+ const baseKey = rootKey === `` ? key : rootKey;
575
585
  const formattedValue = isNestedObject
576
- ? formatObject(value, _indent + 1, { seen: seenNew, colorFmt, key }, _obj)
577
- : formatValue(value, _obj);
586
+ ? formatObject(value, _indent + 1, { colorFmt, rootKey: baseKey }, _obj)
587
+ : formatValue(value, baseKey);
578
588
  return `<br>${nestedIndent}"${key}": ${formattedValue}`;
579
- }).join(`,`);
589
+ }).filter(val => !hasVal(val) || val !== `----`).join(`,`);
580
590
 
581
591
  let result = `{${formattedEntries}<br>${baseIndent}}`;
582
592
  if (!colorFmt) {
@@ -2529,6 +2539,44 @@ const initialControl = async () => {
2529
2539
  delete g_keyObj[key];
2530
2540
  }
2531
2541
  });
2542
+
2543
+ // エディター用のフォーマッター作成
2544
+ const customKeyList = g_headerObj.keyLists.filter(val =>
2545
+ g_keyObj.defaultKeyList.findIndex(key => key === val) < 0);
2546
+
2547
+ customKeyList.forEach(key => {
2548
+ const keyBase = `${key}_0`;
2549
+ const keyCtrlPtn = `${g_keyObj.defaultProp}${keyBase}`;
2550
+ const keyGroup = g_keyObj[`keyGroup${keyBase}`];
2551
+ const keyGroupList = makeDedupliArray(keyGroup.flat());
2552
+ const orgKeyNum = g_keyObj[keyCtrlPtn].length;
2553
+ const baseX = Math.floor(Math.random() * (100 - keyGroupList.length));
2554
+
2555
+ keyGroupList.forEach((keyGroupNo, j) => {
2556
+ const keyN = keyGroupNo === `0` ? key : `${key}_${j + 1}`;
2557
+ const filterCond = (j) => keyGroup[j].findIndex(val => val === keyGroupNo) >= 0;
2558
+ const keyCtrlList = g_keyObj[keyCtrlPtn].filter((val, j) => filterCond(j));
2559
+ const charaList = g_keyObj[`chara${keyBase}`].filter((val, j) => filterCond(j));
2560
+ const colorList = g_keyObj[`color${keyBase}_0`].filter((val, j) => filterCond(j));
2561
+ const keyNum = g_keyObj[keyCtrlPtn].filter((val, j) => filterCond(j)).length;
2562
+
2563
+ g_editorTmp[keyN] = {};
2564
+ g_editorTmp[keyN].id = orgKeyNum * 100 + baseX + j;
2565
+ g_editorTmp[keyN].num = keyNum;
2566
+ g_editorTmp[keyN].chars = keyCtrlList.map(val => g_kCd[val[0]]);
2567
+ g_editorTmp[keyN].keys = keyCtrlList.map(val => g_kCdN[val[0]]).map(val => replaceStr(val, g_escapeStr.editorKey));
2568
+ g_editorTmp[keyN].alternativeKeys = keyCtrlList.map(val => val[1] === 0 ? `` : g_kCdN[val[1]]).map(val => replaceStr(val, g_escapeStr.editorKey));
2569
+ g_editorTmp[keyN].noteNames = charaList.map(val => `${val}_data`);
2570
+ g_editorTmp[keyN].freezeNames = charaList.map(val => {
2571
+ let frzName = replaceStr(val, g_escapeStr.frzName);
2572
+ if (frzName.indexOf(`frz`) === -1 && frzName.indexOf(`foni`) === -1) {
2573
+ frzName = frzName.replaceAll(frzName, `frz${toCapitalize(frzName)}`);
2574
+ }
2575
+ return `${frzName}_data`;
2576
+ });
2577
+ g_editorTmp[keyN].colorGroup = colorList.map(val => val % 3);
2578
+ });
2579
+ });
2532
2580
  };
2533
2581
 
2534
2582
  /**
@@ -5000,10 +5048,12 @@ const dataMgtInit = () => {
5000
5048
  g_stateObj[`dm_${key}`] = C_FLG_OFF;
5001
5049
  g_settings.dataMgtNum[key] = 0;
5002
5050
 
5051
+ const keyWidth = Math.min(Math.max(50, getStrWidth(getKeyName(key), g_limitObj.setLblSiz, getBasicFont())), 80);
5003
5052
  keyListSprite.appendChild(createMgtButton(key, j - 2, 0, {
5004
- w: Math.max(50, getStrWidth(getKeyName(key) + ` `, g_limitObj.setLblSiz, getBasicFont())),
5053
+ w: keyWidth,
5054
+ siz: getFontSize(getKeyName(key), keyWidth, getBasicFont(), g_limitObj.setLblSiz, 10),
5005
5055
  }));
5006
- document.getElementById(`btn${key}`).innerHTML = getKeyName(key);
5056
+ document.getElementById(`btn${toCapitalize(key)}`).innerHTML = getKeyName(key);
5007
5057
 
5008
5058
  keyListSprite.appendChild(createCss2Button(`btnView${key}`, ``, evt => {
5009
5059
  keyList.forEach(keyx => {
@@ -5030,7 +5080,7 @@ const dataMgtInit = () => {
5030
5080
  multiAppend(divRoot,
5031
5081
  createCss2Button(`btnBack`, g_lblNameObj.b_back, () => true,
5032
5082
  Object.assign(g_lblPosObj.btnResetBack, {
5033
- resetFunc: () => prevPage === `title` ? titleInit() : g_moveSettingWindow(false),
5083
+ resetFunc: () => [`title`, `precondition`].includes(prevPage) ? titleInit() : g_moveSettingWindow(false),
5034
5084
  }), g_cssObj.button_Back),
5035
5085
 
5036
5086
  createCss2Button(`btnPrecond`, g_lblNameObj.b_precond, () => true,
@@ -5137,6 +5187,11 @@ const preconditionInit = () => {
5137
5187
  .replace(/[\t\n]/g, ``), 0, 15, g_cssObj.flex_centering),
5138
5188
 
5139
5189
  createDivCss2Label(`lblPrecondView`, viewKeyStorage(`g_rootObj`), g_lblPosObj.lblPrecondView),
5190
+ createCss2Button(`btnPrecondView`, g_lblNameObj.b_copyStorage, () =>
5191
+ copyTextToClipboard(
5192
+ viewKeyStorage(g_settings.preconditions[g_settings.preconditionNum * numOfPrecs + g_settings.preconditionNumSub], ``, false),
5193
+ g_msgInfoObj.I_0007),
5194
+ g_lblPosObj.btnPrecondView, g_cssObj.button_Default, g_cssObj.button_ON),
5140
5195
  );
5141
5196
  setUserSelect($id(`lblPrecondView`), `text`);
5142
5197
 
@@ -5166,6 +5221,7 @@ const preconditionInit = () => {
5166
5221
  }
5167
5222
  lblPrecondView.innerHTML = viewKeyStorage(g_settings.preconditions[g_settings.preconditionNum * numOfPrecs + j]);
5168
5223
  lblPrecondView.scrollTop = 0;
5224
+ g_settings.preconditionNumSub = j;
5169
5225
  evt.target.classList.replace(g_cssObj.button_Default, g_cssObj.button_Reset);
5170
5226
  }, {
5171
5227
  x: g_btnX() + g_btnWidth((j % (numOfPrecs / 2)) / (numOfPrecs / 2 + 1)),
@@ -5185,6 +5241,12 @@ const preconditionInit = () => {
5185
5241
  g_customJsObj.precondition.forEach(func => func());
5186
5242
 
5187
5243
  multiAppend(divRoot,
5244
+
5245
+ // データ管理画面へ移動
5246
+ createCss2Button(`btnReset`, g_lblNameObj.dataReset, () => {
5247
+ dataMgtInit();
5248
+ }, g_lblPosObj.btnReset, g_cssObj.button_Reset),
5249
+
5188
5250
  createCss2Button(`btnBack`, g_lblNameObj.b_back, () => true,
5189
5251
  Object.assign(g_lblPosObj.btnPrecond, {
5190
5252
  resetFunc: () => {
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2025/03/02 (v40.1.0)
8
+ * Revised : 2025/03/08 (v40.3.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -283,6 +283,9 @@ const updateWindowSiz = () => {
283
283
  btnKeyStorage: {
284
284
  x: g_btnX(1) - 140, y: 100 + g_sHeight / 4 + 10, w: 70, h: 20, siz: 16,
285
285
  },
286
+ btnPrecondView: {
287
+ x: g_btnX(1) - 90, y: 110, w: 70, h: 20, siz: 16,
288
+ },
286
289
 
287
290
  /** 設定画面 */
288
291
  btnBack: {
@@ -785,6 +788,18 @@ const g_escapeStr = {
785
788
  [`all[]`, `sumData(g_detailObj.arrowCnt[{0}]) + sumData(g_detailObj.frzCnt[{0}])`],
786
789
  [`maxlife[]`, `g_headerObj.maxLifeVal`],
787
790
  ],
791
+ editorKey: [
792
+ [`ArrowLeft`, `KeyU`],
793
+ [`ArrowDown`, `KeyI`],
794
+ [`ArrowUp`, `Digit8`],
795
+ [`ArrowRight`, `KeyO`],
796
+ [`Space`, `KeyG`],
797
+ [`KeyB`, `KeyH`],
798
+ [`Enter`, `BackSlash`],
799
+ [`ShiftLeft`, `KeyZ`],
800
+ [`ShiftRight`, `Slash`],
801
+ [`Tab`, `KeyQ`],
802
+ ]
788
803
  };
789
804
 
790
805
  /** 設定・オプション画面用共通 */
@@ -1156,8 +1171,9 @@ const g_settings = {
1156
1171
  settingWindowNum: 0,
1157
1172
 
1158
1173
  preconditions: [`g_rootObj`, `g_headerObj`, `g_keyObj`, `g_scoreObj`, `g_workObj`,
1159
- `g_detailObj`, `g_stateObj`, `g_attrObj`],
1174
+ `g_detailObj`, `g_stateObj`, `g_attrObj`, `g_editorTmp`],
1160
1175
  preconditionNum: 0,
1176
+ preconditionNumSub: 0,
1161
1177
  };
1162
1178
 
1163
1179
  g_settings.volumeNum = g_settings.volumes.length - 1;
@@ -2487,6 +2503,7 @@ const g_keyObj = {
2487
2503
  dfPtnNum: 0,
2488
2504
 
2489
2505
  minKeyCtrlNum: 2,
2506
+ defaultKeyList: [],
2490
2507
 
2491
2508
  // キー別ヘッダー
2492
2509
  // - 譜面データ中に出てくる矢印(ノーツ)の種類と順番(ステップゾーン表示順)を管理する
@@ -3023,6 +3040,11 @@ const g_keyObj = {
3023
3040
  // g_keyObj.defaultProp の上書きを禁止
3024
3041
  Object.defineProperty(g_keyObj, `defaultProp`, { writable: false });
3025
3042
 
3043
+ // 既定のキー定義リストを動的に作成
3044
+ Object.keys(g_keyObj)
3045
+ .filter(key => key.startsWith(g_keyObj.defaultProp) && key.endsWith(`_0`))
3046
+ .forEach(key => g_keyObj.defaultKeyList.push(key.split(`_`)[0].slice(g_keyObj.defaultProp.length)));
3047
+
3026
3048
  // キーパターンのコピーリスト
3027
3049
  // ・コピー先:コピー元の順に指定する
3028
3050
  // ・上から順に処理する
@@ -3157,6 +3179,8 @@ g_keycons.groups.forEach(type => {
3157
3179
  tmpName.forEach(property => g_keyObj[`${property.slice(0, -2)}`] = g_keyObj[property].concat());
3158
3180
  });
3159
3181
 
3182
+ const g_editorTmp = {};
3183
+
3160
3184
  // 特殊キーのコピー種 (simple: 代入、multiple: 配列ごと代入)
3161
3185
  // 後でプロパティ削除に影響するため、先頭文字が全く同じ場合は長い方を先に定義する (例: divMax, div)
3162
3186
  const g_keyCopyLists = {
@@ -3447,6 +3471,7 @@ const g_lang_msgInfoObj = {
3447
3471
  I_0004: `musicUrlが設定されていないため、無音モードで再生します`,
3448
3472
  I_0005: `正規のミラー譜面で無いため、ハイスコアは保存されません`,
3449
3473
  I_0006: `ローカルストレージ情報をクリップボードにコピーしました!`,
3474
+ I_0007: `オブジェクト情報をクリップボードにコピーしました!`,
3450
3475
  },
3451
3476
  En: {
3452
3477
  W_0001: `Your browser is not guaranteed to work.<br>
@@ -3501,6 +3526,7 @@ const g_lang_msgInfoObj = {
3501
3526
  I_0004: `Play in silence mode because "musicUrl" is not set`,
3502
3527
  I_0005: `Highscore is not saved because not a regular mirrored chart.`,
3503
3528
  I_0006: `Local storage information copied to clipboard!`,
3529
+ I_0007: `Object information copied to clipboard!`,
3504
3530
  },
3505
3531
  };
3506
3532
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "40.1.0",
3
+ "version": "40.3.0",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "index.js",
6
6
  "scripts": {