danoniplus 40.0.1 → 40.2.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/01
7
+ * Revised : 2025/03/07
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 40.0.1`;
12
- const g_revisedDate = `2025/03/01`;
11
+ const g_version = `Ver 40.2.0`;
12
+ const g_revisedDate = `2025/03/07`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -37,13 +37,41 @@ const current = () => {
37
37
  const targetScript = scripts.find(file => file.src.endsWith(`danoni_main.js`));
38
38
  return targetScript.src;
39
39
  };
40
+
41
+ /**
42
+ * 現在URLのクエリパラメータから指定した値を取得
43
+ * @param {string} _name
44
+ * @returns {string}
45
+ */
46
+ const getQueryParamVal = _name => {
47
+ const param = new URL(location.href).searchParams.get(_name);
48
+ return param !== null ? decodeURIComponent(param.replace(/\+/g, ` `)) : null;
49
+ };
50
+
51
+ // 常時デバッグを許可するドメイン
52
+ const g_reservedDomains = [
53
+ `danonicw.skr.jp`,
54
+ `tickle.cloudfree.jp`,
55
+ ];
56
+ Object.freeze(g_reservedDomains);
57
+
58
+ // 外部参照を許可するドメイン
59
+ const g_referenceDomains = [
60
+ `cwtickle.github.io/danoniplus`,
61
+ `support-v\\d+--danoniplus.netlify.app`,
62
+ ];
63
+ Object.freeze(g_referenceDomains);
64
+
40
65
  const g_rootPath = current().match(/(^.*\/)/)[0];
41
66
  const g_workPath = new URL(location.href).href.match(/(^.*\/)/)[0];
42
- const g_remoteFlg = g_rootPath.match(`^https://cwtickle.github.io/danoniplus/`) !== null ||
43
- g_rootPath.match(/danoniplus.netlify.app/) !== null;
67
+ const g_remoteFlg = g_referenceDomains.some(domain => g_rootPath.match(`^https://${domain}/`) !== null);
68
+
44
69
  const g_randTime = Date.now();
45
70
  const g_isFile = location.href.match(/^file/);
46
71
  const g_isLocal = location.href.match(/^file/) || location.href.indexOf(`localhost`) !== -1;
72
+ const g_isDebug = g_isLocal ||
73
+ g_reservedDomains.some(domain => location.href.match(`^https://${domain}/`) !== null) ||
74
+ getQueryParamVal(`debug`) === `true`;
47
75
  const isLocalMusicFile = _scoreId => g_isFile && !listMatching(getMusicUrl(_scoreId), [`.js`, `.txt`], { suffix: `$` });
48
76
 
49
77
  window.onload = async () => {
@@ -468,44 +496,53 @@ const viewKeyStorage = (_name, _key = ``) => {
468
496
  * オブジェクトのネスト表示処理
469
497
  * @param {Object} _obj
470
498
  * @param {Number} _indent
471
- * @param {WeakSet} [seen=new WeakSet()]
472
- * @param {boolean} [colorFmt=true]
473
- * @param {string} [key='']
499
+ * @param {boolean} [colorFmt=true] フォーマット加工フラグ
500
+ * @param {string} [rootKey=''] オブジェクトの最上位プロパティ名
474
501
  * @param {Object} [_parent=null]
475
502
  * @returns {string}
476
503
  */
477
- const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true, key = `` } = {}, _parent = null) => {
504
+ const formatObject = (_obj, _indent = 0, { colorFmt = true, rootKey = `` } = {}) => {
478
505
  if (_obj === null || typeof _obj !== 'object') {
479
506
  return JSON.stringify(_obj);
480
507
  }
481
- if (seen.has(_obj)) {
482
- return '[Circular]';
483
- }
484
- seen.add(_obj);
485
508
  const baseIndent = getIndent(_indent);
486
509
  const nestedIndent = getIndent(_indent + 1);
487
510
 
488
- // カラーコード、対応キーの色付け処理
489
- const colorCodePattern = /(#|0x)(?:[A-Fa-f0-9]{6}(?:[A-Fa-f0-9]{2})?|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{3})/g;
490
- const formatValue = (_value, _parent) => {
511
+ /**
512
+ * データの装飾処理
513
+ * @param {string|boolean|number|Object} _value
514
+ * @param {string} _rootKey
515
+ * @returns {string}
516
+ */
517
+ const formatValue = (_value, _rootKey) => {
491
518
  if (colorFmt) {
492
- if (typeof _value === 'string') {
493
- _value = escapeHtml(_value);
519
+ if (typeof _value === C_TYP_STRING) {
520
+
521
+ // カラーコードの色付け処理
522
+ _value = escapeHtml(_value).replaceAll(`\n`, `<br>`);
523
+ const colorCodePattern = /(#|0x)(?:[A-Fa-f0-9]{6}(?:[A-Fa-f0-9]{2})?|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{3})/g;
494
524
  if (colorCodePattern.test(_value)) {
495
525
  return _value.replace(colorCodePattern, (match) =>
496
526
  `<span style="color:${match.replace(`0x`, `#`)}">◆</span>${match.replace(`0x`, `#`)}`);
497
527
  }
498
- }
499
- if (Array.isArray(_value)) {
500
- let formattedArray = _value.map(item => formatValue(item, _value));
501
- if (key.startsWith(`keyCtrl`)) {
502
- formattedArray = formattedArray.filter(item => item !== `0`)
503
- .map(item => g_kCd[item] ? `${item}|<span style="color:#ffff66">${g_kCd[item]}</span>` : item);
528
+ } else if (typeof _value === C_TYP_BOOLEAN) {
529
+
530
+ // boolean値の色付け処理
531
+ return (_value ? `<span style="color:#66ff66">&#x2714; true</span>` :
532
+ `<span style="color:#ff9999">&#x274c; false</span>`);
533
+
534
+ } else if (typeof _value === C_TYP_NUMBER) {
535
+
536
+ if (_rootKey.startsWith(`scrollDir`)) {
537
+ // scrollDirXのスクロール方向表示処理
538
+ return _value === 1 ? `1|<span style="color:#ff9999">↑</span>` : `-1|<span style="color:#66ff66">↓</span>`;
539
+
540
+ } else if (_rootKey.startsWith(`keyCtrl`) && !_rootKey.startsWith(`keyCtrlPtn`)) {
541
+ // keyCtrlXの対応キー表示処理
542
+ return (g_kCd[_value] && _value !== 0) ? `${_value}|<span style="color:#ffff66">${g_kCd[_value]}</span>` : `----`;
504
543
  }
505
- return `[${formattedArray.join(`, `)}]`;
506
- }
507
- if (typeof _value === 'object' && _value !== null) {
508
- return formatObject(_value, _indent + 1, { seen, colorFmt, key }, _parent);
544
+ } else if (typeof _value === C_TYP_OBJECT && _value !== null) {
545
+ return formatObject(_value, _indent + 1, { colorFmt, rootKey: _rootKey });
509
546
  }
510
547
  }
511
548
  return JSON.stringify(_value);
@@ -519,7 +556,7 @@ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true
519
556
  if (colorFmt && _obj.length > 100) {
520
557
  const filteredArray = _obj.reduce((result, value, index) => {
521
558
  if (hasVal(value)) {
522
- result.push(`${index}: ${formatValue(value, _obj)}`);
559
+ result.push(`${index}: ${formatValue(value, rootKey)}`);
523
560
  }
524
561
  return result;
525
562
  }, []);
@@ -530,11 +567,11 @@ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true
530
567
  .map(value => {
531
568
  const isNestedObject = typeof value === 'object' && value !== null;
532
569
  return isArrayOfArrays
533
- ? `${nestedIndent}${formatValue(value, _obj)}`
570
+ ? `${nestedIndent}${formatValue(value, rootKey)}`
534
571
  : isNestedObject
535
- ? formatObject(value, _indent + 1, { seen, colorFmt }, _obj)
536
- : formatValue(value, _obj)
537
- }).join(isArrayOfArrays ? `,<br>` : `, `);
572
+ ? formatObject(value, _indent + 1, { colorFmt, rootKey })
573
+ : formatValue(value, rootKey)
574
+ }).filter(val => !hasVal(val) || val !== `----`).join(isArrayOfArrays ? `,<br>` : `, `);
538
575
 
539
576
  return `[${isArrayOfArrays ? `<br>` : ``}${formattedArray}${isArrayOfArrays ? `<br>${baseIndent}` : ''}]`;
540
577
  }
@@ -543,12 +580,12 @@ const formatObject = (_obj, _indent = 0, { seen = new WeakSet(), colorFmt = true
543
580
  const formattedEntries = Object.entries(_obj)
544
581
  .map(([key, value]) => {
545
582
  const isNestedObject = typeof value === 'object' && value !== null;
546
- const seenNew = _parent ? seen : new WeakSet();
583
+ const baseKey = rootKey === `` ? key : rootKey;
547
584
  const formattedValue = isNestedObject
548
- ? formatObject(value, _indent + 1, { seen: seenNew, colorFmt, key }, _obj)
549
- : formatValue(value, _obj);
585
+ ? formatObject(value, _indent + 1, { colorFmt, rootKey: baseKey }, _obj)
586
+ : formatValue(value, baseKey);
550
587
  return `<br>${nestedIndent}"${key}": ${formattedValue}`;
551
- }).join(`,`);
588
+ }).filter(val => !hasVal(val) || val !== `----`).join(`,`);
552
589
 
553
590
  let result = `{${formattedEntries}<br>${baseIndent}}`;
554
591
  if (!colorFmt) {
@@ -825,14 +862,17 @@ const createScText = (_obj, _settingLabel, { displayName = `option`, dfLabel = `
825
862
  * 各画面の汎用ショートカットキー表示
826
863
  * @param {string} _displayName
827
864
  */
828
- const createScTextCommon = _displayName =>
829
- Object.keys(g_btnPatterns[_displayName]).filter(target => document.getElementById(`btn${target}`) !== null)
830
- .forEach(target =>
831
- createScText(document.getElementById(`btn${target}`), target, {
832
- displayName: _displayName, targetLabel: `btn${target}`,
833
- dfLabel: g_lblNameObj[`sc_${_displayName}${target}`] ?? ``,
834
- x: g_btnPatterns[_displayName][target],
835
- }));
865
+ const createScTextCommon = _displayName => {
866
+ if (g_btnPatterns[_displayName]) {
867
+ Object.keys(g_btnPatterns[_displayName]).filter(target => document.getElementById(`btn${target}`) !== null)
868
+ .forEach(target =>
869
+ createScText(document.getElementById(`btn${target}`), target, {
870
+ displayName: _displayName, targetLabel: `btn${target}`,
871
+ dfLabel: g_lblNameObj[`sc_${_displayName}${target}`] ?? ``,
872
+ x: g_btnPatterns[_displayName][target],
873
+ }));
874
+ }
875
+ };
836
876
 
837
877
  /**
838
878
  * ショートカットキー有効化
@@ -849,7 +889,9 @@ const setShortcutEvent = (_displayName, _func = () => true, { displayFlg = true,
849
889
  document.onkeydown = evt => commonKeyDown(evt, _displayName, _func, dfEvtFlg);
850
890
  document.onkeyup = evt => commonKeyUp(evt);
851
891
  };
852
- if (g_initialFlg && g_btnWaitFrame[_displayName].initial) {
892
+ if (!g_btnWaitFrame[_displayName] ||
893
+ g_btnWaitFrame[_displayName].s_frame === 0 ||
894
+ (g_initialFlg && g_btnWaitFrame[_displayName].initial)) {
853
895
  evList();
854
896
  } else {
855
897
  setTimeout(() => {
@@ -1588,7 +1630,9 @@ const createCss2Button = (_id, _text, _func = () => true, {
1588
1630
 
1589
1631
  // ボタン有効化操作
1590
1632
  if (initDisabledFlg) {
1591
- if (g_initialFlg && g_btnWaitFrame[groupName].initial) {
1633
+ if (!g_btnWaitFrame[groupName] ||
1634
+ g_btnWaitFrame[groupName].b_frame === 0 ||
1635
+ (g_initialFlg && g_btnWaitFrame[groupName].initial)) {
1592
1636
  } else {
1593
1637
  style.pointerEvents = C_DIS_NONE;
1594
1638
  setTimeout(() => style.pointerEvents = rest.pointerEvents ?? C_DIS_AUTO,
@@ -2263,16 +2307,6 @@ const copyTextToClipboard = async (_textVal, _msg) => {
2263
2307
  }
2264
2308
  };
2265
2309
 
2266
- /**
2267
- * 現在URLのクエリパラメータから指定した値を取得
2268
- * @param {string} _name
2269
- * @returns {string}
2270
- */
2271
- const getQueryParamVal = _name => {
2272
- const param = new URL(location.href).searchParams.get(_name);
2273
- return param !== null ? decodeURIComponent(param.replace(/\+/g, ` `)) : null;
2274
- };
2275
-
2276
2310
  /**
2277
2311
  * ローディング文字用ラベルの作成
2278
2312
  * @returns {HTMLDivElement}
@@ -5005,7 +5039,7 @@ const dataMgtInit = () => {
5005
5039
  multiAppend(divRoot,
5006
5040
  createCss2Button(`btnBack`, g_lblNameObj.b_back, () => true,
5007
5041
  Object.assign(g_lblPosObj.btnResetBack, {
5008
- resetFunc: () => prevPage === `title` ? titleInit() : g_moveSettingWindow(false),
5042
+ resetFunc: () => [`title`, `precondition`].includes(prevPage) ? titleInit() : g_moveSettingWindow(false),
5009
5043
  }), g_cssObj.button_Back),
5010
5044
 
5011
5045
  createCss2Button(`btnPrecond`, g_lblNameObj.b_precond, () => true,
@@ -5160,6 +5194,12 @@ const preconditionInit = () => {
5160
5194
  g_customJsObj.precondition.forEach(func => func());
5161
5195
 
5162
5196
  multiAppend(divRoot,
5197
+
5198
+ // データ管理画面へ移動
5199
+ createCss2Button(`btnReset`, g_lblNameObj.dataReset, () => {
5200
+ dataMgtInit();
5201
+ }, g_lblPosObj.btnReset, g_cssObj.button_Reset),
5202
+
5163
5203
  createCss2Button(`btnBack`, g_lblNameObj.b_back, () => true,
5164
5204
  Object.assign(g_lblPosObj.btnPrecond, {
5165
5205
  resetFunc: () => {
@@ -6853,7 +6893,8 @@ const getKeyCtrl = (_localStorage, _extraKeyName = ``) => {
6853
6893
  const isUpdate = prevPtn !== -1 && g_keyObj.prevKey !== g_keyObj.currentKey;
6854
6894
  g_keyCopyLists.multiple.filter(header => g_keyObj[`${header}${basePtn}`] !== undefined && isUpdate)
6855
6895
  .forEach(header => g_keyObj[`${header}${copyPtn}`] = structuredClone(g_keyObj[`${header}${basePtn}`]));
6856
- g_keyCopyLists.simple.forEach(header => g_keyObj[`${header}${copyPtn}`] = g_keyObj[`${header}${basePtn}`]);
6896
+ g_keyCopyLists.simple.filter(header => g_keyObj[`${header}${basePtn}`] !== undefined && isUpdate)
6897
+ .forEach(header => g_keyObj[`${header}${copyPtn}`] = g_keyObj[`${header}${basePtn}`]);
6857
6898
 
6858
6899
  g_keycons.groups.forEach(type => {
6859
6900
  let maxPtn = 0;
@@ -10791,8 +10832,8 @@ const mainInit = () => {
10791
10832
  [`lblCredit`, `lblDifName`].forEach(labelName => changeStyle(labelName, g_lblPosObj.musicInfoOFF));
10792
10833
  }
10793
10834
 
10794
- // ローカル時のみフレーム数を残す
10795
- if (!g_isLocal) {
10835
+ // デバッグ時のみフレーム数を残す
10836
+ if (!g_isDebug) {
10796
10837
  lblframe.style.display = C_DIS_NONE;
10797
10838
  }
10798
10839
 
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2025/03/01 (v40.0.1)
8
+ * Revised : 2025/03/02 (v40.1.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -248,7 +248,7 @@ const updateWindowSiz = () => {
248
248
  },
249
249
  btnPrecond: {
250
250
  x: g_btnX(1 / 4), y: g_sHeight - 20, w: g_btnWidth(1 / 4), h: 16, siz: 12,
251
- visibility: getQueryParamVal(`debug`) === `true` ? `visible` : `hidden`,
251
+ visibility: g_isDebug ? `visible` : `hidden`,
252
252
  },
253
253
  btnSafeMode: {
254
254
  x: g_btnX(), siz: 18,
@@ -2326,22 +2326,32 @@ const g_shortcutObj = {
2326
2326
  // b_frame: ボタンの有効化フレーム数、s_frame: ショートカットキーの有効化フレーム数
2327
2327
  // initial: 初回のみ有効化時間を設定する場合、trueを設定
2328
2328
  const g_btnWaitFrame = {
2329
- initial: { b_frame: 0, s_frame: 0 },
2330
- title: { b_frame: 0, s_frame: 0 },
2331
- dataMgt: { b_frame: 0, s_frame: 0 },
2332
- precondition: { b_frame: 0, s_frame: 0 },
2333
- option: { b_frame: 0, s_frame: 0, initial: true },
2334
- difSelector: { b_frame: 0, s_frame: 0 },
2335
- settingsDisplay: { b_frame: 0, s_frame: 0 },
2336
- exSetting: { b_frame: 0, s_frame: 0 },
2337
- keyConfig: { b_frame: 0, s_frame: 30 },
2338
- loading: { b_frame: 0, s_frame: 0 },
2339
- loadingIos: { b_frame: 0, s_frame: 0 },
2340
- main: { b_frame: 0, s_frame: 0 },
2341
- result: { b_frame: 0, s_frame: 120 },
2329
+ initial: {},
2330
+ title: {},
2331
+ dataMgt: {},
2332
+ precondition: {},
2333
+ option: { initial: true },
2334
+ difSelector: {},
2335
+ settingsDisplay: {},
2336
+ exSetting: {},
2337
+ keyConfig: { s_frame: 30 },
2338
+ loading: {},
2339
+ loadingIos: {},
2340
+ main: {},
2341
+ result: { s_frame: 120 },
2342
2342
  };
2343
+ Object.keys(g_btnWaitFrame).forEach(key => {
2344
+ if (!g_btnWaitFrame[key].b_frame) {
2345
+ g_btnWaitFrame[key].b_frame = 0;
2346
+ }
2347
+ if (!g_btnWaitFrame[key].s_frame) {
2348
+ g_btnWaitFrame[key].s_frame = 0;
2349
+ }
2350
+ });
2343
2351
 
2344
2352
  // 主要ボタンのリスト
2353
+ // - btn + プロパティ名に合致するボタンid名に対して、
2354
+ // どの位置(X方向)にショートカット名を表示するかを設定
2345
2355
  const g_btnPatterns = {
2346
2356
  title: { Start: 0, Comment: -10 },
2347
2357
  dataMgt: { Back: 0, Environment: -35, Highscores: -35, CustomKey: -35, Others: -35 },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "40.0.1",
3
+ "version": "40.2.0",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "index.js",
6
6
  "scripts": {