danoniplus 39.5.0 → 39.6.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/02/15
7
+ * Revised : 2025/02/16
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 39.5.0`;
12
- const g_revisedDate = `2025/02/15`;
11
+ const g_version = `Ver 39.6.0`;
12
+ const g_revisedDate = `2025/02/16`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -189,6 +189,7 @@ let g_langStorage = {};
189
189
  // ローカルストレージ設定 (作品別)
190
190
  let g_localStorage;
191
191
  let g_localStorageUrl;
192
+ let g_localStorageMgt;
192
193
 
193
194
  // ローカルストレージ設定 (ドメイン・キー別)
194
195
  let g_localKeyStorage;
@@ -424,6 +425,60 @@ const parseStorageData = (_keyName, _default = {}) => {
424
425
  }
425
426
  }
426
427
 
428
+ /**
429
+ * 画面表示用インデント処理
430
+ * @param {number} _level
431
+ * @returns {string}
432
+ */
433
+ const getIndent = (_level) => ' '.repeat(_level * 4);
434
+
435
+ /**
436
+ * ストレージ情報の取得
437
+ * @param {string} _name g_storageFuncの実行キー名
438
+ * @param {string} _key g_storageFuncの実行キーの引数
439
+ * @returns {string}
440
+ */
441
+ const viewKeyStorage = (_name, _key = ``) => {
442
+
443
+ // キャッシュ設定
444
+ if (!viewKeyStorage.cache) {
445
+ viewKeyStorage.cache = new Map();
446
+ }
447
+ const cacheKey = _key + _name;
448
+ if (viewKeyStorage.cache.has(cacheKey)) {
449
+ return viewKeyStorage.cache.get(cacheKey);
450
+ }
451
+ const result = formatObject(g_storageFunc.get(_name)(_key));
452
+ viewKeyStorage.cache.set(cacheKey, result);
453
+ return result;
454
+ }
455
+
456
+ /**
457
+ * オブジェクトのネスト表示処理
458
+ * @param {Object} _obj
459
+ * @param {Number} _indent
460
+ * @param {WeakSet} _seen
461
+ * @returns {string}
462
+ */
463
+ const formatObject = (_obj, _indent = 0, _seen = new WeakSet()) => {
464
+ if (_obj === null || typeof _obj !== 'object') {
465
+ return JSON.stringify(_obj);
466
+ }
467
+ if (_seen.has(_obj)) {
468
+ return '[Circular]';
469
+ }
470
+ _seen.add(_obj);
471
+ const baseIndent = getIndent(_indent);
472
+ const nestedIndent = getIndent(_indent + 1);
473
+ const formattedEntries = Object.entries(_obj)
474
+ .map(([key, value]) => {
475
+ const isNestedObject = typeof value === 'object' && value !== null && !Array.isArray(value);
476
+ const formattedValue = isNestedObject ? formatObject(value, _indent + 1, _seen) : JSON.stringify(value);
477
+ return `<br>${nestedIndent}"${key}": ${formattedValue}`;
478
+ }).join(`,`);
479
+ return `{${formattedEntries}<br>${baseIndent}}`;
480
+ }
481
+
427
482
  /**
428
483
  * 重複を排除した配列の生成
429
484
  * @param {any[]} _array1
@@ -1107,13 +1162,27 @@ const getStrWidth = (_str, _fontsize, _font) => {
1107
1162
  */
1108
1163
  const getFontSize = (_str, _maxWidth, _font = getBasicFont(), _maxFontsize = 64, _minFontsize = 5) => {
1109
1164
  for (let siz = _maxFontsize; siz >= _minFontsize; siz--) {
1110
- if (_maxWidth >= getStrWidth(_str, siz, _font)) {
1165
+ if (_maxWidth >= getStrWidth(getLongestStr(_str?.split(`<br>`)), siz, _font)) {
1111
1166
  return siz;
1112
1167
  }
1113
1168
  }
1114
1169
  return _minFontsize;
1115
1170
  };
1116
1171
 
1172
+ /**
1173
+ * 配列中から最も長い文字列を抽出
1174
+ * @param {string[]} _array
1175
+ * @returns {string}
1176
+ */
1177
+ const getLongestStr = _array => {
1178
+ if (_array === undefined) {
1179
+ return ``;
1180
+ }
1181
+ return _array.reduce((longest, current) => {
1182
+ return current.length > longest.length ? current : longest;
1183
+ }, ``);
1184
+ }
1185
+
1117
1186
  /**
1118
1187
  * 補足説明部分のラベル作成
1119
1188
  * @param {string} _id
@@ -2374,13 +2443,22 @@ const loadLocalStorage = () => {
2374
2443
  g_localeObj.val = g_langStorage.locale;
2375
2444
  g_localeObj.num = g_localeObj.list.findIndex(val => val === g_localeObj.val);
2376
2445
  }
2446
+ if (g_langStorage.safeMode === undefined) {
2447
+ g_langStorage.safeMode = C_FLG_OFF;
2448
+ }
2377
2449
  Object.assign(g_msgInfoObj, g_lang_msgInfoObj[g_localeObj.val]);
2378
2450
  Object.assign(g_kCd, g_lang_kCd[g_localeObj.val]);
2379
2451
 
2380
2452
  // 作品別ローカルストレージの読込
2381
- g_localStorage = parseStorageData(g_localStorageUrl, {
2382
- adjustment: 0, hitPosition: 0, volume: 100, highscores: {},
2383
- });
2453
+ if (g_langStorage.safeMode === C_FLG_OFF) {
2454
+ g_localStorage = parseStorageData(g_localStorageUrl, {
2455
+ adjustment: 0, hitPosition: 0, volume: 100, highscores: {},
2456
+ });
2457
+ } else {
2458
+ g_localStorage = {};
2459
+ g_stateObj.dataSaveFlg = false;
2460
+ makeWarningWindow(g_msgInfoObj.W_0031);
2461
+ }
2384
2462
 
2385
2463
  // Adjustment, Volume, Appearance, Opacity, HitPosition初期値設定
2386
2464
  checkLocalParam(`adjustment`, C_TYP_FLOAT, g_settings.adjustmentNum);
@@ -4698,6 +4776,7 @@ const setWindowStyle = (_text, _bkColor, _textColor, _align = C_ALIGN_LEFT, { _x
4698
4776
 
4699
4777
  const dataMgtInit = () => {
4700
4778
  clearWindow(true);
4779
+ const prevPage = g_currentPage;
4701
4780
  g_currentPage = `dataMgt`;
4702
4781
 
4703
4782
  multiAppend(divRoot,
@@ -4707,7 +4786,7 @@ const dataMgtInit = () => {
4707
4786
  `<div class="settings_Title">DATA</div><div class="settings_Title2">MANAGEMENT</div>`
4708
4787
  .replace(/[\t\n]/g, ``), 0, 15, g_cssObj.flex_centering),
4709
4788
 
4710
- createDescDiv(`dataDelMsg`, g_lblNameObj.dataDeleteDesc),
4789
+ createDescDiv(`dataDelMsg`, g_lblNameObj[`dataDelete${g_langStorage.safeMode}Desc`]),
4711
4790
  );
4712
4791
 
4713
4792
  // 各ボタン用のスプライトを作成
@@ -4760,61 +4839,6 @@ const dataMgtInit = () => {
4760
4839
  }, g_cssObj[`button_${cssBgList[g_settings.dataMgtNum[_name]]}`], g_cssObj[`button_${cssBarList[g_settings.dataMgtNum[_name]]}`]);
4761
4840
  };
4762
4841
 
4763
- /**
4764
- * キー別ストレージ情報の取得
4765
- * @param {string} _key
4766
- * @returns {string}
4767
- */
4768
- const viewKeyStorage = _key => {
4769
-
4770
- // キャッシュ設定
4771
- if (!viewKeyStorage.cache) {
4772
- viewKeyStorage.cache = new Map();
4773
- }
4774
- if (viewKeyStorage.cache.has(_key)) {
4775
- return viewKeyStorage.cache.get(_key);
4776
- }
4777
-
4778
- let keyStorage = parseStorageData(`danonicw-${_key}k`);
4779
- if (Object.keys(keyStorage).length === 0) {
4780
-
4781
- // キー別の情報が見つからない場合は作品別の情報から検索
4782
- Object.keys(g_localStorage).filter(val => val.endsWith(_key))
4783
- .forEach(val => keyStorage[val] = g_localStorage[val]);
4784
- if (Object.keys(keyStorage).length === 0) {
4785
- return ``;
4786
- }
4787
- }
4788
- const result = formatObject(keyStorage);
4789
- viewKeyStorage.cache.set(_key, result);
4790
- return result;
4791
- }
4792
-
4793
- /**
4794
- * 画面表示用インデント処理
4795
- * @param {number} _level
4796
- * @returns {string}
4797
- */
4798
- const getIndent = (_level) => '&nbsp;'.repeat(_level * 4);
4799
-
4800
- /**
4801
- * オブジェクトのネスト表示処理
4802
- * @param {Object} _obj
4803
- * @param {Number} _indent
4804
- * @returns {string}
4805
- */
4806
- const formatObject = (_obj, _indent = 0) => {
4807
- const baseIndent = getIndent(_indent);
4808
- const nestedIndent = getIndent(_indent + 1);
4809
- const formattedEntries = Object.entries(_obj)
4810
- .map(([key, value]) => {
4811
- const isNestedObject = typeof value === 'object' && value !== null && !Array.isArray(value);
4812
- const formattedValue = isNestedObject ? formatObject(value, _indent + 1) : JSON.stringify(value);
4813
- return `<br>${nestedIndent}"${key}": ${formattedValue}`;
4814
- }).join(`,`);
4815
- return `{${formattedEntries}<br>${baseIndent}}`;
4816
- }
4817
-
4818
4842
  multiAppend(optionsprite,
4819
4843
  createMgtLabel(`workData`, 0),
4820
4844
  createMgtButton(`environment`, 1.5, 0),
@@ -4828,15 +4852,11 @@ const dataMgtInit = () => {
4828
4852
  })
4829
4853
  );
4830
4854
 
4831
- // カスタムキー定義のストレージデータを表示から除去
4832
- const settingStorage = {};
4833
- Object.keys(g_localStorage).filter(val => !listMatching(val, g_settings.keyStorages.concat(`setColor`), { prefix: `^` }))
4834
- .forEach(val => settingStorage[val] = g_localStorage[val]);
4835
-
4855
+ g_localStorageMgt = parseStorageData(g_localStorageUrl);
4836
4856
  multiAppend(divRoot,
4837
4857
  createDivCss2Label(`lblWorkDataView`,
4838
- formatObject(settingStorage), g_lblPosObj.lblWorkDataView),
4839
- createDivCss2Label(`lblKeyDataView`, viewKeyStorage(g_headerObj.keyLabels[0]), g_lblPosObj.lblKeyDataView),
4858
+ viewKeyStorage(`workStorage`), g_lblPosObj.lblWorkDataView),
4859
+ createDivCss2Label(`lblKeyDataView`, viewKeyStorage(`keyStorage`, g_headerObj.keyLabels[0]), g_lblPosObj.lblKeyDataView),
4840
4860
  );
4841
4861
  setUserSelect($id(`lblWorkDataView`), `text`);
4842
4862
  setUserSelect($id(`lblKeyDataView`), `text`);
@@ -4849,7 +4869,7 @@ const dataMgtInit = () => {
4849
4869
  keyListSprite.appendChild(createMgtButton(key, j - 2, 0, {
4850
4870
  w: Math.max(50, getStrWidth(getKeyName(key) + ` `, g_limitObj.setLblSiz, getBasicFont())),
4851
4871
  func: () => {
4852
- lblKeyDataView.innerHTML = viewKeyStorage(key);
4872
+ lblKeyDataView.innerHTML = viewKeyStorage(`keyStorage`, key);
4853
4873
  lblTargetKey.innerHTML = `(${getKeyName(key)})`;
4854
4874
  },
4855
4875
  }));
@@ -4861,10 +4881,19 @@ const dataMgtInit = () => {
4861
4881
 
4862
4882
  multiAppend(divRoot,
4863
4883
  createCss2Button(`btnBack`, g_lblNameObj.b_back, () => true,
4864
- Object.assign(g_lblPosObj.btnBack, {
4865
- animationName: (g_initialFlg ? `` : `smallToNormalY`), resetFunc: () => titleInit(),
4884
+ Object.assign(g_lblPosObj.btnResetBack, {
4885
+ resetFunc: () => prevPage === `title` ? titleInit() : g_moveSettingWindow(false),
4866
4886
  }), g_cssObj.button_Back),
4867
4887
 
4888
+ createCss2Button(`btnSafeMode`, g_lblNameObj.b_safeMode +
4889
+ (g_langStorage.safeMode === C_FLG_ON ? C_FLG_OFF : C_FLG_ON), () => {
4890
+ if (window.confirm(g_msgObj[`safeMode${g_langStorage.safeMode}Confirm`])) {
4891
+ g_langStorage.safeMode = g_langStorage.safeMode === C_FLG_ON ? C_FLG_OFF : C_FLG_ON;
4892
+ localStorage.setItem(`danoni-locale`, JSON.stringify(g_langStorage));
4893
+ location.reload();
4894
+ }
4895
+ }, g_lblPosObj.btnSafeMode, g_cssObj.button_Setting),
4896
+
4868
4897
  createCss2Button(`btnReset`, g_lblNameObj.b_cReset, () => {
4869
4898
  reloadFlg = false;
4870
4899
  const backupData = new Map();
@@ -4877,9 +4906,9 @@ const dataMgtInit = () => {
4877
4906
  `\n\n${selectedData.map(val => `- ${g_msgObj[val] || g_msgObj.keyTypes.split('{0}').join(val)}`).join(`\n`)}`)) {
4878
4907
  selectedData.forEach(key => {
4879
4908
  if (g_resetFunc.has(key)) {
4880
- backupData.set(key, JSON.parse(JSON.stringify(g_localStorage)));
4909
+ backupData.set(key, JSON.parse(JSON.stringify(g_localStorageMgt)));
4881
4910
  g_resetFunc.get(key)();
4882
- localStorage.setItem(g_localStorageUrl, JSON.stringify(g_localStorage));
4911
+ localStorage.setItem(g_localStorageUrl, JSON.stringify(g_localStorageMgt));
4883
4912
 
4884
4913
  } else if (keyList.includes(key)) {
4885
4914
  const storage = parseStorageData(`danonicw-${key}k`);
@@ -4889,9 +4918,9 @@ const dataMgtInit = () => {
4889
4918
  g_settings.keyStorages.forEach(val => delete storage[val]);
4890
4919
  localStorage.setItem(`danonicw-${key}k`, JSON.stringify(storage));
4891
4920
  } else {
4892
- backupData.set(`XX` + key, JSON.parse(JSON.stringify(g_localStorage)));
4893
- g_settings.keyStorages.forEach(val => delete g_localStorage[`${val}${key}`]);
4894
- localStorage.setItem(g_localStorageUrl, JSON.stringify(g_localStorage));
4921
+ backupData.set(`XX` + key, JSON.parse(JSON.stringify(g_localStorageMgt)));
4922
+ g_settings.keyStorages.forEach(val => delete g_localStorageMgt[`${val}${key}`]);
4923
+ localStorage.setItem(g_localStorageUrl, JSON.stringify(g_localStorageMgt));
4895
4924
  }
4896
4925
  }
4897
4926
  });
@@ -4899,6 +4928,7 @@ const dataMgtInit = () => {
4899
4928
  sessionStorage.setItem('resetBackup', JSON.stringify(Array.from(backupData.entries())));
4900
4929
  }
4901
4930
  }, Object.assign(g_lblPosObj.btnResetN, {
4931
+ visibility: g_langStorage.safeMode === C_FLG_OFF ? C_DIS_INHERIT : `hidden`,
4902
4932
  resetFunc: () => {
4903
4933
  if (reloadFlg) {
4904
4934
  location.reload();
@@ -4912,8 +4942,8 @@ const dataMgtInit = () => {
4912
4942
  if (backup && window.confirm(g_msgObj.dataRestoreConfirm)) {
4913
4943
  backup.forEach(([key, data]) => {
4914
4944
  if (g_resetFunc.has(key) || keyList.includes(key.slice(`XX`.length))) {
4915
- Object.assign(g_localStorage, data);
4916
- localStorage.setItem(g_localStorageUrl, JSON.stringify(g_localStorage));
4945
+ Object.assign(g_localStorageMgt, data);
4946
+ localStorage.setItem(g_localStorageUrl, JSON.stringify(g_localStorageMgt));
4917
4947
  } else if (keyList.includes(key)) {
4918
4948
  localStorage.setItem(`danonicw-${key}k`, JSON.stringify(data));
4919
4949
  }
@@ -4978,6 +5008,7 @@ const commonSettingBtn = _labelName => {
4978
5008
  createCss2Button(`btnSave`, g_lblNameObj.dataSave, evt => switchSave(evt),
4979
5009
  Object.assign(g_lblPosObj.btnSave, {
4980
5010
  cxtFunc: evt => switchSave(evt),
5011
+ visibility: g_langStorage.safeMode === C_FLG_OFF ? C_DIS_INHERIT : `hidden`,
4981
5012
  }), g_cssObj.button_Default, (g_stateObj.dataSaveFlg ? g_cssObj.button_ON : g_cssObj.button_OFF)),
4982
5013
 
4983
5014
  // データ管理画面へ移動
@@ -10075,7 +10106,9 @@ const getArrowSettings = () => {
10075
10106
 
10076
10107
  if (g_stateObj.dataSaveFlg) {
10077
10108
  // ローカルストレージへAdjustment, HitPosition, Volume設定を保存
10109
+ // 変更が確定した時点で表示用のキャッシュを解放
10078
10110
  g_storeSettings.forEach(setting => g_localStorage[setting] = g_stateObj[setting]);
10111
+ viewKeyStorage.cache = new Map();
10079
10112
  localStorage.setItem(g_localStorageUrl, JSON.stringify(g_localStorage));
10080
10113
  }
10081
10114
 
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2025/02/15 (v39.5.0)
8
+ * Revised : 2025/02/16 (v39.6.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -242,6 +242,12 @@ const updateWindowSiz = () => {
242
242
  },
243
243
 
244
244
  /** データ管理 */
245
+ btnResetBack: {
246
+ x: g_btnX(), y: g_sHeight - 20, w: g_btnWidth(1 / 4), h: 16, siz: 12,
247
+ },
248
+ btnSafeMode: {
249
+ x: g_btnX(), siz: 18,
250
+ },
245
251
  dataDelMsg: {
246
252
  x: 0, y: 65, w: g_sWidth, h: 20, siz: g_limitObj.mainSiz,
247
253
  },
@@ -1290,17 +1296,48 @@ const resetXY = () => {
1290
1296
  */
1291
1297
  const g_resetFunc = new Map([
1292
1298
  ['highscores', () => {
1293
- delete g_localStorage.highscores;
1294
- g_localStorage.highscores = {};
1299
+ delete g_localStorageMgt.highscores;
1300
+ g_localStorageMgt.highscores = {};
1295
1301
  }],
1296
- ['environment', () => g_settings.environments.forEach(key => delete g_localStorage[key])],
1297
- [`customKey`, () => Object.keys(g_localStorage)
1302
+ ['environment', () => g_settings.environments.forEach(key => delete g_localStorageMgt[key])],
1303
+ [`customKey`, () => Object.keys(g_localStorageMgt)
1298
1304
  .filter(key => listMatching(key, g_settings.keyStorages.concat(`setColor`), { prefix: `^` }))
1299
- .forEach(key => delete g_localStorage[key])],
1300
- [`others`, () => Object.keys(g_localStorage)
1305
+ .forEach(key => delete g_localStorageMgt[key])],
1306
+ [`others`, () => Object.keys(g_localStorageMgt)
1301
1307
  .filter(key => !g_settings.environments.includes(key) && key !== `highscores` &&
1302
1308
  !listMatching(key, g_settings.keyStorages.concat(`setColor`), { prefix: `^` }))
1303
- .forEach(key => delete g_localStorage[key])],
1309
+ .forEach(key => delete g_localStorageMgt[key])],
1310
+ ]);
1311
+
1312
+ /**
1313
+ * ストレージ管理関数
1314
+ */
1315
+ const g_storageFunc = new Map([
1316
+
1317
+ // 作品別のストレージ情報
1318
+ ['workStorage', (_key) => {
1319
+ const settingStorage = {};
1320
+
1321
+ // カスタムキー定義のストレージデータを表示から除去
1322
+ Object.keys(g_localStorageMgt).filter(val => !listMatching(val, g_settings.keyStorages.concat(`setColor`), { prefix: `^` }))
1323
+ .forEach(val => settingStorage[val] = g_localStorageMgt[val]);
1324
+ return settingStorage;
1325
+ }],
1326
+
1327
+ // キー別のストレージ情報
1328
+ ['keyStorage', (_key) => {
1329
+ let keyStorage = parseStorageData(`danonicw-${_key}k`);
1330
+ if (Object.keys(keyStorage).length === 0) {
1331
+
1332
+ // キー別の情報が見つからない場合は作品別の情報から検索
1333
+ Object.keys(g_localStorageMgt).filter(val => val.endsWith(_key))
1334
+ .forEach(val => keyStorage[val] = g_localStorageMgt[val]);
1335
+ if (Object.keys(keyStorage).length === 0) {
1336
+ return ``;
1337
+ }
1338
+ }
1339
+ return keyStorage;
1340
+ }],
1304
1341
  ]);
1305
1342
 
1306
1343
  /**
@@ -3311,6 +3348,8 @@ const g_lang_msgInfoObj = {
3311
3348
  また、Fadein を使用した場合は通常よりズレが発生することがあります。<br>
3312
3349
  音源ファイルを js/txt 化するか、サーバー上動作とすれば解消します。(W-0012)`,
3313
3350
  W_0021: `クリップボードのコピーに失敗しました。`,
3351
+ W_0031: `セーフモード適用中です。ローカルストレージ情報を使わない設定になっています。<br>
3352
+ 「Data Management」から解除が可能です。(W-0031)`,
3314
3353
 
3315
3354
  E_0011: `アーティスト名が未入力です。(E-0011)`,
3316
3355
  E_0012: `曲名情報が未設定です。(E-0012)<br>
@@ -3361,6 +3400,9 @@ const g_lang_msgInfoObj = {
3361
3400
  It can be solved by converting the sound source file to encoded data (js, txt) or
3362
3401
  operating it on the server. (W-0012)`,
3363
3402
  W_0021: `Failed to copy the clipboard.`,
3403
+ W_0031: `Safe Mode is being applied. <br>
3404
+ The setting is set to not use local storage information <br>
3405
+ and can be removed from Data Management. (W-0031)`,
3364
3406
 
3365
3407
  E_0011: `The artist name is not set. (E-0011)`,
3366
3408
  E_0012: `The song title information is not set. (E-0012)<br>
@@ -3441,6 +3483,7 @@ const g_lblNameObj = {
3441
3483
  b_keyConfig: `KeyConfig`,
3442
3484
  b_play: `PLAY!`,
3443
3485
  b_reset: `Reset Key`,
3486
+ b_safeMode: `Safe Mode -> `,
3444
3487
  b_undo: `Restore`,
3445
3488
  b_settings: `To Settings`,
3446
3489
  b_copy: `CopyResult`,
@@ -3683,7 +3726,8 @@ const g_linkObj = {
3683
3726
  */
3684
3727
  const g_lang_lblNameObj = {
3685
3728
  Ja: {
3686
- dataDeleteDesc: `消去したいデータの種類を選んで「Reset」を押してください`,
3729
+ dataDeleteOFFDesc: `消去したいデータの種類を選んで「Reset」を押してください`,
3730
+ dataDeleteONDesc: `セーフモード適用中はデータ消去は行えません。変更するにはセーフモードを解除してください`,
3687
3731
 
3688
3732
  kcDesc: `[{0}:スキップ / {1}:(代替キーのみ)キー無効化]`,
3689
3733
  kcShuffleDesc: `番号をクリックでシャッフルグループ、矢印をクリックでカラーグループを変更`,
@@ -3726,7 +3770,8 @@ const g_lang_lblNameObj = {
3726
3770
  securityUrl: `https://github.com/cwtickle/danoniplus/security/policy`,
3727
3771
  },
3728
3772
  En: {
3729
- dataDeleteDesc: `Select the type of data you wish to delete and press "Reset".`,
3773
+ dataDeleteOFFDesc: `Select the type of data you wish to delete and press "Reset".`,
3774
+ dataDeleteONDesc: `Data erasure cannot be performed while safe mode is applied. <br>Please deactivate the safe mode to change the data.`,
3730
3775
 
3731
3776
  kcDesc: `[{0}:Skip / {1}:Key invalidation (Alternate keys only)]`,
3732
3777
  kcShuffleDesc: `Click the number to change the shuffle group, and click the arrow to change the color.`,
@@ -3796,6 +3841,8 @@ const g_lang_msgObj = {
3796
3841
 
3797
3842
  dataResetConfirm: `選択したローカル設定をクリアします。よろしいですか?`,
3798
3843
  dataRestoreConfirm: `ローカル設定を前回の状態に戻します(1回限り)。よろしいですか?\n消去した設定によっては今の設定が上書きされることがあります。`,
3844
+ safeModeONConfirm: `セーフモードを解除して、ローカルストレージ情報を利用します。\nよろしいですか?`,
3845
+ safeModeOFFConfirm: `セーフモードを設定して、ローカルストレージを使わずにリロードします。\nよろしいですか?`,
3799
3846
  keyResetConfirm: `キーを初期配置に戻します。よろしいですか?`,
3800
3847
  highscResetConfirm: `この譜面のハイスコアを消去します。よろしいですか?`,
3801
3848
  colorCopyConfirm: `フリーズアローの配色を矢印色に置き換えます\n(通常・ヒット時双方を置き換えます)。よろしいですか?`,
@@ -3879,12 +3926,14 @@ const g_lang_msgObj = {
3879
3926
 
3880
3927
  environment: `Initialize ${g_settings.environments.map(v => toCapitalize(v)).join(`, `)} settings.`,
3881
3928
  highscores: `Initializes the high score of all charts. \nIf you want to initialize each chart individually, \nplease do so from the Highscore view in the Settings screen.`,
3882
- customKey: `Delete stored data related to all custom keymodes. Use this option when you cannot delete individual KeyData from the following KeyData`,
3929
+ customKey: `Delete stored data related to all custom keymodes. \nUse this option when you cannot delete individual KeyData from the following KeyData.`,
3883
3930
  others: `Delete non-standard stored data.`,
3884
3931
  keyTypes: `Deletes the stored data (except color settings) for Key: {0}.`,
3885
3932
 
3886
3933
  dataResetConfirm: `Delete the selected local settings. Is it OK?`,
3887
3934
  dataRestoreConfirm: `Restore local settings to previous state (one time only). Is it OK?\nSome deleted settings may overwrite the current settings.`,
3935
+ safeModeONConfirm: `Exit safe mode and use local storage information. Is it OK?`,
3936
+ safeModeOFFConfirm: `Set safe mode and reload without local storage. Is it OK?`,
3888
3937
  keyResetConfirm: `Resets the assigned key to the initial state. Is it OK?`,
3889
3938
  highscResetConfirm: `Erases the high score for this chart. Is it OK?`,
3890
3939
  colorCopyConfirm: `Replace freeze arrow color scheme with arrow color\n(replace both normal and hit). Is this OK?`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "39.5.0",
3
+ "version": "39.6.0",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "index.js",
6
6
  "scripts": {