🏠 Home 

Greasy Fork is available in English.

YouTubeライブ コメント流し

YouTubeライブのチャットを動画上に流すやつ


Installer dette script?
  1. // ==UserScript==
  2. // @name YouTubeライブ コメント流し
  3. // @namespace https://midra.me
  4. // @version 2.0.0
  5. // @description YouTubeライブのチャットを動画上に流すやつ
  6. // @author Midra
  7. // @license MIT
  8. // @match https://www.youtube.com/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  10. // @run-at document-body
  11. // @grant GM_getValue
  12. // @grant GM.getValue
  13. // @grant GM_setValue
  14. // @grant GM.setValue
  15. // @grant GM_registerMenuCommand
  16. // @compatible chrome >= 80
  17. // @compatible safari >= 14.1
  18. // @compatible firefox >= 80
  19. // ==/UserScript==
  20. /******/ (function() { // webpackBootstrap
  21. /******/ "use strict";
  22. var __webpack_exports__ = {};
  23. ;// CONCATENATED MODULE: ../../Library/FlowComments/src/constants.ts
  24. /****************************************
  25. * デフォルト値
  26. */
  27. const CONFIG = {
  28. /** フォントファミリー */
  29. FONT_FAMILY: [
  30. 'Arial',
  31. '"MS Pゴシック"', 'MS PGothic',
  32. '"ヒラギノ角ゴシック"', '"Hiragino Sans"',
  33. // '"游ゴシック体"', 'YuGothic', '"游ゴシック"', '"Yu Gothic"',
  34. 'Gulim', '"Malgun Gothic"',
  35. '"黑体"', 'SimHei',
  36. 'system-ui', '-apple-system',
  37. 'sans-serif',
  38. ].join(),
  39. /** フォントの太さ */
  40. FONT_WEIGHT: '600',
  41. /** フォントの拡大率 */
  42. FONT_SCALE: 0.7,
  43. /** フォントのY軸のオフセット */
  44. FONT_OFFSET_Y: 0.15,
  45. /** テキストの色 */
  46. TEXT_COLOR: '#fff',
  47. /** テキストシャドウの色 */
  48. TEXT_SHADOW_COLOR: '#000',
  49. /** テキストシャドウのぼかし */
  50. TEXT_SHADOW_BLUR: 1,
  51. /** テキスト間の余白(配列形式の場合) */
  52. TEXT_MARGIN: 0.2,
  53. /** Canvasのクラス名 */
  54. CANVAS_CLASSNAME: 'mid-FlowComments',
  55. /** Canvasの比率 */
  56. CANVAS_RATIO: 16 / 9,
  57. /** Canvasの解像度 */
  58. CANVAS_RESOLUTION: 720,
  59. /** 解像度のリスト */
  60. RESOLUTION_LIST: [240, 360, 480, 720],
  61. /** コメントの表示時間 */
  62. CMT_DISPLAY_DURATION: 6000,
  63. /** コメントの最大数(0は無制限) */
  64. CMT_LIMIT: 0,
  65. /** 行数 */
  66. LINES: 11,
  67. /** 比率の自動調整 */
  68. AUTO_RESIZE: true,
  69. /** 解像度の自動調整 */
  70. AUTO_RESOLUTION: true,
  71. };
  72. /****************************************
  73. * コメントの種類
  74. */
  75. var TYPE;
  76. (function (TYPE) {
  77. TYPE[TYPE["FLOW"] = 0] = "FLOW";
  78. TYPE[TYPE["TOP"] = 1] = "TOP";
  79. TYPE[TYPE["BOTTOM"] = 2] = "BOTTOM";
  80. })(TYPE || (TYPE = {}));
  81. const ITEM_DEFAULT_OPTION = {
  82. position: TYPE.FLOW,
  83. duration: CONFIG.CMT_DISPLAY_DURATION,
  84. };
  85. const DEFAULT_OPTION = {
  86. resolution: CONFIG.CANVAS_RESOLUTION,
  87. lines: CONFIG.LINES,
  88. limit: CONFIG.CMT_LIMIT,
  89. autoResize: CONFIG.AUTO_RESIZE,
  90. autoResolution: CONFIG.AUTO_RESOLUTION,
  91. smoothRender: false,
  92. };
  93. const DEFAULT_STYLE = {
  94. fontFamily: CONFIG.FONT_FAMILY,
  95. fontWeight: CONFIG.FONT_WEIGHT,
  96. fontScale: 1,
  97. color: CONFIG.TEXT_COLOR,
  98. shadowColor: CONFIG.TEXT_SHADOW_COLOR,
  99. shadowBlur: CONFIG.TEXT_SHADOW_BLUR,
  100. opacity: 1,
  101. };
  102. ;// CONCATENATED MODULE: ../../Library/FlowComments/src/modules/imageCache.ts
  103. var __classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  104. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  105. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  106. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  107. };
  108. var _a, _ImageCache_OPTION, _ImageCache_cache;
  109. /****************************************
  110. * @classdesc 画像キャッシュ管理用
  111. */
  112. class ImageCache {
  113. /****************************************
  114. * キャッシュ追加
  115. * @param url URL
  116. * @param img 画像
  117. */
  118. static add(url, img) {
  119. // 削除
  120. if (__classPrivateFieldGet(this, _a, "f", _ImageCache_OPTION).maxSize < Object.keys(__classPrivateFieldGet(this, _a, "f", _ImageCache_cache)).length) {
  121. let delCacheUrl;
  122. Object.keys(__classPrivateFieldGet(this, _a, "f", _ImageCache_cache)).forEach(key => {
  123. if (delCacheUrl === undefined ||
  124. __classPrivateFieldGet(this, _a, "f", _ImageCache_cache)[key].lastUsed < __classPrivateFieldGet(this, _a, "f", _ImageCache_cache)[delCacheUrl].lastUsed) {
  125. delCacheUrl = key;
  126. }
  127. });
  128. this.dispose(delCacheUrl);
  129. }
  130. // 追加
  131. __classPrivateFieldGet(this, _a, "f", _ImageCache_cache)[url] = {
  132. img: img,
  133. lastUsed: Date.now(),
  134. };
  135. }
  136. /****************************************
  137. * 画像が存在するか
  138. * @param url URL
  139. */
  140. static has(url) {
  141. return url !== undefined && __classPrivateFieldGet(this, _a, "f", _ImageCache_cache).hasOwnProperty(url);
  142. }
  143. /****************************************
  144. * 画像を取得
  145. * @param url URL
  146. * @returns 画像
  147. */
  148. static async get(url) {
  149. return new Promise(async (resolve, reject) => {
  150. if (this.has(url)) {
  151. __classPrivateFieldGet(this, _a, "f", _ImageCache_cache)[url].lastUsed = Date.now();
  152. resolve(__classPrivateFieldGet(this, _a, "f", _ImageCache_cache)[url].img);
  153. }
  154. else {
  155. try {
  156. let img = new Image();
  157. img.addEventListener('load', ({ target }) => {
  158. if (target instanceof HTMLImageElement) {
  159. this.add(target.src, target);
  160. resolve(__classPrivateFieldGet(this, _a, "f", _ImageCache_cache)[target.src].img);
  161. }
  162. else {
  163. reject();
  164. }
  165. });
  166. img.addEventListener('error', reject);
  167. img.src = url;
  168. img = null;
  169. }
  170. catch (e) {
  171. reject(e);
  172. }
  173. }
  174. });
  175. }
  176. /****************************************
  177. * 画像を解放
  178. * @param url URL
  179. */
  180. static dispose(url) {
  181. if (url !== undefined && this.has(url)) {
  182. __classPrivateFieldGet(this, _a, "f", _ImageCache_cache)[url].img.remove();
  183. delete __classPrivateFieldGet(this, _a, "f", _ImageCache_cache)[url];
  184. }
  185. }
  186. }
  187. _a = ImageCache;
  188. /** オプション(デフォルト値) */
  189. _ImageCache_OPTION = { value: {
  190. maxSize: 50,
  191. } };
  192. /** キャッシュ */
  193. _ImageCache_cache = { value: {} };
  194. ;// CONCATENATED MODULE: ../../Library/FlowComments/src/modules/image.ts
  195. /****************************************
  196. * @classdesc `FlowComments.Item`用の画像クラス
  197. */
  198. class image_Image {
  199. /****************************************
  200. * コンストラクタ
  201. * @param url URL
  202. * @param alt 代替テキスト
  203. */
  204. constructor(url, alt) {
  205. this._url = url;
  206. this._alt = alt || '';
  207. }
  208. get url() { return this._url; }
  209. get alt() { return this._alt; }
  210. /****************************************
  211. * 画像を取得
  212. */
  213. async get() {
  214. try {
  215. return (await ImageCache.get(this._url));
  216. }
  217. catch (e) {
  218. return this._alt;
  219. }
  220. }
  221. }
  222. ;// CONCATENATED MODULE: ../../Library/FlowComments/src/modules/util.ts
  223. /****************************************
  224. * @classdesc ユーティリティ
  225. */
  226. class Util {
  227. /****************************************
  228. * オブジェクトのプロパティからnullとundefinedを除去
  229. * @param obj オブジェクト
  230. */
  231. static filterObject(obj) {
  232. if (obj !== undefined && obj !== null && typeof obj === 'object' && !Array.isArray(obj)) {
  233. Object.keys(obj).forEach(key => {
  234. if (obj[key] === undefined || obj[key] === null) {
  235. delete obj[key];
  236. }
  237. else {
  238. this.filterObject(obj[key]);
  239. }
  240. });
  241. }
  242. }
  243. /****************************************
  244. * Canvasにスタイルを適用
  245. * @param ctx CanvasRenderingContext2D
  246. * @param style スタイル
  247. * @param fontSize フォントサイズ
  248. */
  249. static setStyleToCanvas(ctx, style, fontSize) {
  250. ctx.textBaseline = 'middle';
  251. ctx.lineJoin = 'round';
  252. ctx.font = `${style.fontWeight} ${fontSize * style.fontScale}px ${style.fontFamily}`;
  253. ctx.fillStyle = style.color;
  254. ctx.shadowColor = style.shadowColor;
  255. ctx.shadowBlur = fontSize / 16 * style.shadowBlur;
  256. ctx.globalAlpha = style.opacity;
  257. }
  258. }
  259. ;// CONCATENATED MODULE: ../../Library/FlowComments/src/modules/item.ts
  260. /****************************************
  261. * @classdesc 流すコメント
  262. * @example
  263. * // idを指定する場合
  264. * const fcItem1 = new FlowCommentsItem('1518633760656605184', 'ウルトラソウッ')
  265. * // idを指定しない場合
  266. * const fcItem2 = new FlowCommentsItem(Symbol(), 'みどらんかわいい!')
  267. */
  268. class Item {
  269. /****************************************
  270. * コンストラクタ
  271. * @param id コメントID
  272. * @param content コメント本文
  273. * @param [option] オプション
  274. * @param [style] スタイル
  275. */
  276. constructor(id, content, option, style) {
  277. /** 座標 */
  278. this.position = {
  279. x: 0,
  280. y: 0,
  281. xp: 0,
  282. offsetY: 0,
  283. };
  284. /**
  285. * 描画サイズ
  286. * @type {{ width: number; height: number; }}
  287. */
  288. this.size = {
  289. width: 0,
  290. height: 0,
  291. };
  292. /** 実際に流すときの距離 */
  293. this.scrollWidth = 0;
  294. /** 行番号 */
  295. this.line = 0;
  296. Util.filterObject(option);
  297. Util.filterObject(style);
  298. this._id = id;
  299. this._content = Array.isArray(content) ? content.filter(v => v) : content;
  300. this._option = { ...ITEM_DEFAULT_OPTION, ...option };
  301. if (this._option.position === TYPE.FLOW) {
  302. this._actualDuration = this._option.duration * 1.5;
  303. }
  304. else {
  305. this._actualDuration = this._option.duration;
  306. }
  307. this._style = style;
  308. this._canvas = document.createElement('canvas');
  309. }
  310. get id() { return this._id; }
  311. get content() { return this._content; }
  312. get style() { return this._style; }
  313. get option() { return this._option; }
  314. get actualDuration() { return this._actualDuration; }
  315. get canvas() { return this._canvas; }
  316. get top() { return this.position?.y || 0; }
  317. get bottom() {
  318. return this.position !== undefined && this.size !== undefined
  319. ? this.position.y + this.size.height
  320. : 0;
  321. }
  322. get left() { return this.position?.x || 0; }
  323. get right() {
  324. return this.position !== undefined && this.size !== undefined
  325. ? this.position.x + this.size.width
  326. : 0;
  327. }
  328. get rect() {
  329. return {
  330. width: this.size?.width || 0,
  331. height: this.size?.height || 0,
  332. top: this.top,
  333. bottom: this.bottom,
  334. left: this.left,
  335. right: this.right,
  336. };
  337. }
  338. dispose() {
  339. this._canvas?.remove();
  340. }
  341. }
  342. ;// CONCATENATED MODULE: ../../Library/FlowComments/src/modules/main.ts
  343. var main_classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  344. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  345. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  346. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  347. };
  348. var __classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  349. if (kind === "m") throw new TypeError("Private method is not writable");
  350. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  351. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  352. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  353. };
  354. var _Main_instances, main_a, _Main_id_cnt, _Main_updateCommentsStyle, _Main_floor, _Main_initializeComment, _Main_renderComment, _Main_update, _Main_loop;
  355. // import * as PIXI from 'pixi.js'
  356. /****************************************
  357. * @classdesc コメントを流すやつ
  358. * @example
  359. * // 準備
  360. * const fc = new FlowComments.Main()
  361. * document.body.appendChild(fc.canvas)
  362. * fc.start()
  363. *
  364. * // コメントを流す(追加する)
  365. * fc.pushComment(new FlowComments.Item(Symbol(), 'Hello world!'))
  366. */
  367. class Main {
  368. /****************************************
  369. * コンストラクタ
  370. * @param [option] オプション
  371. * @param [style] スタイル
  372. */
  373. constructor(option, style) {
  374. _Main_instances.add(this);
  375. // 初期化
  376. this.initialize(option, style);
  377. }
  378. get id() { return this._id; }
  379. get style() { return { ...DEFAULT_STYLE, ...this._style }; }
  380. get option() { return { ...DEFAULT_OPTION, ...this._option }; }
  381. get canvas() { return this._canvas; }
  382. get context2d() { return this._context2d; }
  383. get comments() { return this._comments; }
  384. get lineHeight() { return this._canvas instanceof HTMLCanvasElement ? this._canvas.height / this.option.lines : 0; }
  385. get fontSize() { return this.lineHeight * CONFIG.FONT_SCALE; }
  386. get isStarted() { return this._animReqId !== undefined; }
  387. /****************************************
  388. * 初期化(インスタンス生成時には不要)
  389. * @param [option] オプション
  390. * @param [style] スタイル
  391. */
  392. initialize(option, style) {
  393. var _b, _c;
  394. this.dispose();
  395. // ID割り当て
  396. this._id = __classPrivateFieldSet(_b = Main, main_a, (_c = main_classPrivateFieldGet(_b, main_a, "f", _Main_id_cnt), ++_c), "f", _Main_id_cnt);
  397. // Canvas生成
  398. this._canvas = document.createElement('canvas');
  399. this._canvas.classList.add(CONFIG.CANVAS_CLASSNAME);
  400. this._canvas.dataset.fcid = this._id.toString();
  401. // CanvasRenderingContext2D
  402. this._context2d = this._canvas.getContext('2d');
  403. // コメント一覧
  404. this._comments = [];
  405. // サイズ変更を監視
  406. this._resizeObs = new ResizeObserver(entries => {
  407. entries.forEach(entry => {
  408. if (this._canvas === undefined)
  409. return;
  410. const { width, height } = entry.contentRect;
  411. // Canvasのサイズ(比率)を自動で調整
  412. if (this.option.autoResize) {
  413. const rect_before = this._canvas.width / this._canvas.height;
  414. const rect_resized = width / height;
  415. if (0.01 < Math.abs(rect_before - rect_resized)) {
  416. this.resizeCanvas();
  417. }
  418. }
  419. // Canvasの解像度を自動で調整
  420. if (this.option.autoResolution) {
  421. const resolution = CONFIG.RESOLUTION_LIST.find(v => height <= v);
  422. if (Number.isFinite(resolution) && this.option.resolution !== resolution) {
  423. this.changeOption({ resolution: resolution });
  424. }
  425. }
  426. });
  427. });
  428. this._resizeObs.observe(this._canvas);
  429. // オプションをセット
  430. this.changeOption(option);
  431. // スタイルをセット
  432. this.changeStyle(style);
  433. }
  434. /****************************************
  435. * オプションを変更
  436. * @param option オプション
  437. */
  438. changeOption(option) {
  439. Util.filterObject(option);
  440. this._option = { ...this._option, ...option };
  441. if (option !== undefined && option !== null) {
  442. this.resizeCanvas();
  443. }
  444. }
  445. /****************************************
  446. * スタイルを変更
  447. * @param [style] スタイル
  448. */
  449. changeStyle(style) {
  450. Util.filterObject(style);
  451. this._style = { ...this._style, ...style };
  452. if (style !== undefined && style !== null) {
  453. main_classPrivateFieldGet(this, _Main_instances, "m", _Main_updateCommentsStyle).call(this);
  454. }
  455. }
  456. /****************************************
  457. * Canvasをリサイズ
  458. */
  459. resizeCanvas() {
  460. const { width, height } = this._canvas.getBoundingClientRect();
  461. const { resolution } = this.option;
  462. const ratio = (width === 0 && height === 0) ? CONFIG.CANVAS_RATIO : (width / height);
  463. this._canvas.width = resolution * ratio;
  464. this._canvas.height = resolution;
  465. // Canvasのスタイルをリセット
  466. main_classPrivateFieldGet(this, _Main_instances, "m", _Main_updateCommentsStyle).call(this);
  467. }
  468. /****************************************
  469. * Canvasのスタイルをリセット
  470. */
  471. resetCanvasStyle() {
  472. this.changeStyle(DEFAULT_STYLE);
  473. }
  474. /****************************************
  475. * コメントを追加(流す)
  476. * @param comment コメント
  477. */
  478. async pushComment(comment) {
  479. if (this.isStarted === false ||
  480. document.visibilityState === 'hidden')
  481. return;
  482. //----------------------------------------
  483. // 画面内に表示するコメントを制限
  484. //----------------------------------------
  485. if (0 < this.option.limit && this.option.limit <= this._comments.length) {
  486. this._comments.splice(0, this._comments.length - this.option.limit)[0];
  487. }
  488. //----------------------------------------
  489. // `FCItem`を初期化
  490. //----------------------------------------
  491. await main_classPrivateFieldGet(this, _Main_instances, "m", _Main_initializeComment).call(this, comment);
  492. //----------------------------------------
  493. // コメント表示行を計算
  494. //----------------------------------------
  495. const spd_pushCmt = comment.scrollWidth / comment.option.duration;
  496. // [[0, 0], [1, 0], ~ , [10, 0]] ([line, cnt])
  497. const lines_over = [...Array(this.option.lines)].map((_, i) => [i, 0]);
  498. this._comments.forEach(cmt => {
  499. // 残り表示時間
  500. const leftTime = cmt.option.duration * (1 - cmt.position.xp);
  501. // コメント追加時に重なる or 重なる予定かどうか
  502. const isOver = comment.left - spd_pushCmt * leftTime <= 0 ||
  503. comment.left <= cmt.right;
  504. if (isOver && cmt.line < this.option.lines) {
  505. lines_over[cmt.line][1]++;
  506. }
  507. });
  508. // 重なった頻度を元に昇順で並べ替える
  509. const lines_sort = lines_over.sort(([, cntA], [, cntB]) => cntA - cntB);
  510. comment.line = lines_sort[0][0];
  511. comment.position.y = this.lineHeight * comment.line;
  512. //----------------------------------------
  513. // コメントを追加
  514. //----------------------------------------
  515. this._comments.push(comment);
  516. }
  517. /****************************************
  518. * コメント流しを開始
  519. */
  520. start() {
  521. if (this._animReqId === undefined) {
  522. this._animReqId = window.requestAnimationFrame(main_classPrivateFieldGet(this, _Main_instances, "m", _Main_loop).bind(this));
  523. }
  524. }
  525. /****************************************
  526. * コメント流しを停止
  527. */
  528. stop() {
  529. if (this._animReqId !== undefined) {
  530. window.cancelAnimationFrame(this._animReqId);
  531. delete this._animReqId;
  532. }
  533. }
  534. /****************************************
  535. * 解放(初期化してCanvasを削除)
  536. */
  537. dispose() {
  538. this.stop();
  539. this._canvas?.remove();
  540. this._resizeObs?.disconnect();
  541. }
  542. }
  543. main_a = Main, _Main_instances = new WeakSet(), _Main_updateCommentsStyle = function _Main_updateCommentsStyle() {
  544. // Canvasをリセット
  545. this._context2d?.clearRect(0, 0, this._canvas.width, this._canvas.height);
  546. // コメントを再初期化・描画
  547. this._comments.forEach(cmt => {
  548. main_classPrivateFieldGet(this, _Main_instances, "m", _Main_initializeComment).call(this, cmt);
  549. main_classPrivateFieldGet(this, _Main_instances, "m", _Main_renderComment).call(this, cmt);
  550. });
  551. }, _Main_floor = function _Main_floor(num) {
  552. return this._option?.smoothRender ? num : (num | 0);
  553. }, _Main_initializeComment =
  554. /****************************************
  555. * `FCItem`を初期化
  556. * @param comment コメント
  557. */
  558. async function _Main_initializeComment(comment) {
  559. const ctx = comment.canvas.getContext('2d');
  560. if (ctx === null)
  561. return;
  562. ctx.clearRect(0, 0, comment.canvas.width, comment.canvas.height);
  563. const style = { ...this.style, ...comment.style };
  564. const drawFontSize = this.fontSize * style.fontScale;
  565. const margin = drawFontSize * CONFIG.TEXT_MARGIN;
  566. // スタイルを適用
  567. Util.setStyleToCanvas(ctx, style, this.fontSize);
  568. const aryWidth = [];
  569. //----------------------------------------
  570. // サイズを計算
  571. //----------------------------------------
  572. for (const cont of comment.content) {
  573. // 文字列
  574. if (typeof cont === 'string') {
  575. aryWidth.push(ctx.measureText(cont).width);
  576. }
  577. // 画像
  578. else if (cont instanceof image_Image) {
  579. const img = await cont.get();
  580. if (img instanceof HTMLImageElement) {
  581. const ratio = img.width / img.height;
  582. aryWidth.push(drawFontSize * ratio);
  583. }
  584. else if (img !== undefined) {
  585. aryWidth.push(ctx.measureText(img).width);
  586. }
  587. else {
  588. aryWidth.push(1);
  589. }
  590. }
  591. }
  592. // コメントの各プロパティを計算
  593. comment.size.width = aryWidth.reduce((a, b) => a + b);
  594. comment.size.width += margin * (aryWidth.length - 1);
  595. comment.size.height = this.lineHeight;
  596. comment.scrollWidth = this._canvas.width + comment.size.width;
  597. comment.position.x = this._canvas.width - comment.scrollWidth * comment.position.xp;
  598. comment.position.y = this.lineHeight * comment.line;
  599. comment.position.offsetY = this.lineHeight / 2 * (1 + CONFIG.FONT_OFFSET_Y);
  600. // Canvasのサイズを設定
  601. comment.canvas.width = comment.size.width;
  602. comment.canvas.height = comment.size.height;
  603. // スタイルを再適用(上でリセットされる)
  604. Util.setStyleToCanvas(ctx, style, this.fontSize);
  605. //----------------------------------------
  606. // コメントを描画
  607. //----------------------------------------
  608. let dx = 0;
  609. for (let idx = 0; idx < comment.content.length; idx++) {
  610. if (0 < idx) {
  611. dx += margin;
  612. }
  613. const cont = comment.content[idx];
  614. // 文字列
  615. if (typeof cont === 'string') {
  616. ctx.fillText(cont, main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, dx), main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, comment.position.offsetY));
  617. }
  618. // 画像
  619. else if (cont instanceof image_Image) {
  620. const img = await cont.get();
  621. if (img instanceof HTMLImageElement) {
  622. ctx.drawImage(img, main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, dx), main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, (comment.size.height - drawFontSize) / 2), main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, aryWidth[idx]), main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, drawFontSize));
  623. }
  624. else if (img !== undefined) {
  625. ctx.fillText(img, main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, dx), main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, comment.position.offsetY));
  626. }
  627. else {
  628. ctx.fillText('', main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, dx), main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, comment.position.offsetY));
  629. }
  630. }
  631. dx += aryWidth[idx];
  632. }
  633. }, _Main_renderComment = function _Main_renderComment(comment) {
  634. this._context2d?.drawImage(comment.canvas, main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, comment.position.x), main_classPrivateFieldGet(this, _Main_instances, "m", _Main_floor).call(this, comment.position.y));
  635. }, _Main_update = function _Main_update(time) {
  636. // Canvasをリセット
  637. this._context2d?.clearRect(0, 0, this._canvas.width, this._canvas.height);
  638. this._comments.forEach((cmt, idx, ary) => {
  639. // コメントを流し始めた時間
  640. if (cmt.startTime === undefined) {
  641. cmt.startTime = time;
  642. }
  643. // コメントを流し始めて経過した時間
  644. const elapsedTime = time - cmt.startTime;
  645. if (elapsedTime <= cmt.actualDuration) {
  646. // コメントの座標を更新(流すコメント)
  647. if (cmt.option.position === TYPE.FLOW) {
  648. cmt.position.xp = elapsedTime / cmt.option.duration;
  649. cmt.position.x = this._canvas.width - cmt.scrollWidth * cmt.position.xp;
  650. }
  651. // コメントを描画
  652. main_classPrivateFieldGet(this, _Main_instances, "m", _Main_renderComment).call(this, cmt);
  653. }
  654. else {
  655. // 表示時間を超えたら消す
  656. cmt.dispose();
  657. ary.splice(idx, 1)[0];
  658. }
  659. });
  660. }, _Main_loop = function _Main_loop(time) {
  661. main_classPrivateFieldGet(this, _Main_instances, "m", _Main_update).call(this, time);
  662. if (this._animReqId !== undefined) {
  663. this._animReqId = window.requestAnimationFrame(main_classPrivateFieldGet(this, _Main_instances, "m", _Main_loop).bind(this));
  664. }
  665. };
  666. /** インスタンスに割り当てられるIDのカウント用 */
  667. _Main_id_cnt = { value: 0 };
  668. ;// CONCATENATED MODULE: ../../Library/FlowComments/src/modules/core.ts
  669. ;// CONCATENATED MODULE: ../../Library/FlowComments/src/index.ts
  670. ;// CONCATENATED MODULE: ./src/constants.ts
  671. /**
  672. * チャットのタイプ
  673. */
  674. var CHAT_TYPE;
  675. (function (CHAT_TYPE) {
  676. /** テキスト */
  677. CHAT_TYPE[CHAT_TYPE["TEXT"] = 0] = "TEXT";
  678. /** スーパーチャット */
  679. CHAT_TYPE[CHAT_TYPE["PAID"] = 1] = "PAID";
  680. /** スーパーチャット(ステッカー) */
  681. CHAT_TYPE[CHAT_TYPE["PAID_STICKER"] = 2] = "PAID_STICKER";
  682. /** メンバーシップ */
  683. CHAT_TYPE[CHAT_TYPE["MEMBERSHIP"] = 3] = "MEMBERSHIP";
  684. })(CHAT_TYPE || (CHAT_TYPE = {}));
  685. /**
  686. * チャットのタイプをタグに紐付ける
  687. */
  688. const PAIR_CHAT_TAGNAME_TYPE = {
  689. 'yt-live-chat-text-message-renderer': CHAT_TYPE.TEXT,
  690. 'yt-live-chat-paid-message-renderer': CHAT_TYPE.PAID,
  691. 'yt-live-chat-paid-sticker-renderer': CHAT_TYPE.PAID_STICKER,
  692. 'yt-live-chat-membership-item-renderer': CHAT_TYPE.MEMBERSHIP,
  693. };
  694. /**
  695. * 投稿者のタイプ
  696. */
  697. var AUTHOR_TYPE;
  698. (function (AUTHOR_TYPE) {
  699. /** 一般ユーザー */
  700. AUTHOR_TYPE[AUTHOR_TYPE["USER"] = 0] = "USER";
  701. /** オーナー */
  702. AUTHOR_TYPE[AUTHOR_TYPE["OWNER"] = 1] = "OWNER";
  703. /** モデレーター */
  704. AUTHOR_TYPE[AUTHOR_TYPE["MODERATOR"] = 2] = "MODERATOR";
  705. /** メンバー */
  706. AUTHOR_TYPE[AUTHOR_TYPE["MEMBER"] = 3] = "MEMBER";
  707. })(AUTHOR_TYPE || (AUTHOR_TYPE = {}));
  708. /**
  709. * 投稿者のタイプを`author-type`属性に紐付ける
  710. */
  711. const PAIR_AUTHOR_ATTR_TYPE = {
  712. '': AUTHOR_TYPE.USER,
  713. 'owner': AUTHOR_TYPE.OWNER,
  714. 'moderator': AUTHOR_TYPE.MODERATOR,
  715. 'member': AUTHOR_TYPE.MEMBER,
  716. };
  717. /**
  718. * カラーコード
  719. */
  720. const COLOR = {
  721. /** 一般ユーザー */
  722. USER: '#ffffff',
  723. /** オーナー */
  724. OWNER: '#ffd600',
  725. /** モデレーター */
  726. MODERATOR: '#5e84f1',
  727. /** メンバー */
  728. MEMBER: '#4ae064',
  729. };
  730. /**
  731. * セレクタ
  732. */
  733. const SELECTOR = {
  734. /** 投稿者名 */
  735. AUTHOR_NAME: '#author-name',
  736. /** アバター画像 */
  737. AUTHOR_PHOTO: '#author-photo img',
  738. /** モデレーターバッジ */
  739. AUTHOR_BADGE: '#chat-badges img',
  740. /** スーパーチャット */
  741. PAID_PURCHASE: '#purchase-amount, #purchase-amount-chip',
  742. /** テキスト */
  743. MESSAGE: '#message',
  744. };
  745. const SVG_SETTING = '<svg viewBox="0 0 24 24" style="fill: #fff;"><g class="style-scope yt-icon"><path d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,8c-2.21,0-4,1.79-4,4s1.79,4,4,4s4-1.79,4-4 S14.21,8,12,8L12,8z M13.22,3l0.55,2.2l0.13,0.51l0.5,0.18c0.61,0.23,1.19,0.56,1.72,0.98l0.4,0.32l0.5-0.14l2.17-0.62l1.22,2.11 l-1.63,1.59l-0.37,0.36l0.08,0.51c0.05,0.32,0.08,0.64,0.08,0.98s-0.03,0.66-0.08,0.98l-0.08,0.51l0.37,0.36l1.63,1.59l-1.22,2.11 l-2.17-0.62l-0.5-0.14l-0.4,0.32c-0.53,0.43-1.11,0.76-1.72,0.98l-0.5,0.18l-0.13,0.51L13.22,21h-2.44l-0.55-2.2l-0.13-0.51 l-0.5-0.18C9,17.88,8.42,17.55,7.88,17.12l-0.4-0.32l-0.5,0.14l-2.17,0.62L3.6,15.44l1.63-1.59l0.37-0.36l-0.08-0.51 C5.47,12.66,5.44,12.33,5.44,12s0.03-0.66,0.08-0.98l0.08-0.51l-0.37-0.36L3.6,8.56l1.22-2.11l2.17,0.62l0.5,0.14l0.4-0.32 C8.42,6.45,9,6.12,9.61,5.9l0.5-0.18l0.13-0.51L10.78,3H13.22 M14,2h-4L9.26,4.96c-0.73,0.27-1.4,0.66-2,1.14L4.34,5.27l-2,3.46 l2.19,2.13C4.47,11.23,4.44,11.61,4.44,12s0.03,0.77,0.09,1.14l-2.19,2.13l2,3.46l2.92-0.83c0.6,0.48,1.27,0.87,2,1.14L10,22h4 l0.74-2.96c0.73-0.27,1.4-0.66,2-1.14l2.92,0.83l2-3.46l-2.19-2.13c0.06-0.37,0.09-0.75,0.09-1.14s-0.03-0.77-0.09-1.14l2.19-2.13 l-2-3.46L16.74,6.1c-0.6-0.48-1.27-0.87-2-1.14L14,2L14,2z" class="style-scope yt-icon"></path></g></svg>';
  746. ;// CONCATENATED MODULE: ./src/util/getAuthorTypeFromAttr.ts
  747. /****************************************
  748. * 属性から投稿者のタイプを取得
  749. */
  750. /* harmony default export */ var getAuthorTypeFromAttr = ((attr) => {
  751. const type = PAIR_AUTHOR_ATTR_TYPE[attr || ''];
  752. return typeof type === 'number' ? type : AUTHOR_TYPE.USER;
  753. });
  754. ;// CONCATENATED MODULE: ./src/util/extractChatData.ts
  755. /****************************************
  756. * ライブチャットのデータを抽出
  757. */
  758. /* harmony default export */ var extractChatData = ((target) => {
  759. const authorName = target.querySelector(SELECTOR.AUTHOR_NAME);
  760. const authorPhoto = target.querySelector(SELECTOR.AUTHOR_PHOTO);
  761. const authorBadge = target.querySelector(SELECTOR.AUTHOR_BADGE);
  762. const id = target.id || '';
  763. const author = {
  764. type: getAuthorTypeFromAttr(target.getAttribute('author-type')),
  765. name: authorName?.textContent?.trim() || null,
  766. photo: authorPhoto?.src || null,
  767. badge: authorBadge?.src || null,
  768. badgeAlt: authorBadge?.alt || null,
  769. };
  770. const message = target.querySelector(SELECTOR.MESSAGE);
  771. const items = Array.from(message?.childNodes || []).map(node => {
  772. if (node.nodeType === Node.TEXT_NODE) {
  773. return {
  774. type: 'text',
  775. text: node.textContent || '',
  776. src: null,
  777. alt: null,
  778. };
  779. }
  780. else if (node instanceof HTMLImageElement) {
  781. return {
  782. type: 'image',
  783. text: null,
  784. src: node.src,
  785. alt: node.alt,
  786. };
  787. }
  788. }).reduce((r###lt, current) => {
  789. // ['分割された', '文字列', image] → ['分割された文字列', image] (一部省略)
  790. if (current !== void 0 &&
  791. (current.text || current.src) !== '') {
  792. const prev = r###lt[r###lt.length - 1];
  793. if (prev !== void 0 &&
  794. prev.type === 'text' &&
  795. current.type === 'text') {
  796. prev.text += current.text;
  797. }
  798. else {
  799. r###lt.push(current);
  800. }
  801. }
  802. return r###lt;
  803. }, []);
  804. const paid = {
  805. purchase: target.querySelector(SELECTOR.PAID_PURCHASE)?.textContent?.trim() || null,
  806. color: target.style.getPropertyValue('--yt-live-chat-paid-message-primary-color') ||
  807. target.style.getPropertyValue('--yt-live-chat-paid-sticker-chip-background-color') ||
  808. null,
  809. };
  810. return {
  811. id: id,
  812. author: author,
  813. items: items,
  814. paid: paid,
  815. };
  816. });
  817. ;// CONCATENATED MODULE: ./src/util/getChatTypeFromTagName.ts
  818. /****************************************
  819. * タグからチャットのタイプを取得
  820. */
  821. /* harmony default export */ var getChatTypeFromTagName = ((tagName) => {
  822. const type = PAIR_CHAT_TAGNAME_TYPE[tagName || ''];
  823. return typeof type === 'number' ? type : null;
  824. });
  825. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/types.ts
  826. const isConfigItemData = (data) => {
  827. if (data instanceof Object) {
  828. return (Object.keys(data).length === 3 &&
  829. data.hasOwnProperty('checked') &&
  830. data.hasOwnProperty('value') &&
  831. data.hasOwnProperty('default'));
  832. }
  833. return false;
  834. };
  835. const isConfigJsonData = (data) => {
  836. if (data instanceof Object) {
  837. return (Object.keys(data).length === 2 &&
  838. data.hasOwnProperty('version') &&
  839. data.hasOwnProperty('data'));
  840. }
  841. return false;
  842. };
  843. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/constants.ts
  844. const SVG_CHECKMARK = '<svg class="midconfig-svg-checkmark" width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9.86 17.997a1.002 1.002 0 0 1-.73-.32l-4.86-5.17a1.001 1.001 0 0 1 1.46-1.37l4.12 4.39 8.41-9.2a1 1 0 1 1 1.48 1.34l-9.14 10a1.002 1.002 0 0 1-.73.33h-.01Z"></path></svg>';
  845. const SVG_ARROW_DOWN = '<svg class="midconfig-svg-arrow-down" width="30" height="30" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 16.001a1 1 0 0 1-.64-.23l-6-5a1.001 1.001 0 0 1 1.28-1.54l5.36 4.48 5.36-4.32a1 1 0 0 1 1.41.15 1 1 0 0 1-.14 1.46l-6 4.83a1 1 0 0 1-.63.17Z"></path></svg>';
  846. const STYLE = '#midconfig{display:flex;flex-direction:column;flex-wrap:nowrap;justify-content:space-between;width:100%;height:100%;border-radius:10px;background-color:var(--back1);border:1px solid var(--text3);box-shadow:1px 1px 10px -2px var(--text3);overflow:hidden}#midconfig{--accent1: #2389ff;--accent2: #238aff26;--accent-text: #fff;--back1: #fff;--text1: #3c3c3c;--text2: #8a8a8a;--text3: #e0e0e0;--red1: #ff3456;--red2: #ff345626}#midconfig[theme=dark]{--accent1: #298cff;--accent2: #298cff36;--accent-text: #fff;--back1: #333;--text1: #f1f1f1;--text2: #a0a0a0;--text3: #505050}@media(prefers-color-scheme: dark){#midconfig[theme=auto]{--accent1: #298cff;--accent2: #298cff36;--accent-text: #fff;--back1: #333;--text1: #f1f1f1;--text2: #a0a0a0;--text3: #505050}}#midconfig #midconfig,#midconfig *,#midconfig ::after,#midconfig ::before{transition:150ms ease-in-out}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=text],#midconfig .midconfig-select-container>select{padding:0 10px;border:1px solid var(--text3);border-radius:8px;background-color:rgba(0,0,0,0)}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-label-container>label>span,#midconfig .midconfig-main>.midconfig-page-item .midconfig-group>.midconfig-group-header>span,#midconfig .midconfig-tab>.midconfig-tab-item,#midconfig .midconfig-button,#midconfig .midconfig-select-container>select{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}#midconfig ::-webkit-scrollbar{width:7px}#midconfig ::-webkit-scrollbar-track{background-color:rgba(0,0,0,0);margin:1px 0}#midconfig ::-webkit-scrollbar-thumb{background-color:var(--text2);border-radius:3px;border-right:1px solid rgba(0,0,0,0);border-left:1px solid rgba(0,0,0,0);background-clip:padding-box}#midconfig *{scrollbar-width:thin;scrollbar-color:var(--text2) rgba(0,0,0,0)}#midconfig,#midconfig *,#midconfig ::after,#midconfig ::before{margin:0;padding:0;box-sizing:border-box;font-family:-apple-system,sans-serif;font-size:14px;font-weight:400;color:var(--text1)}#midconfig :not(input){-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#midconfig svg{display:inline-block;fill:var(--text2);pointer-events:none}#midconfig input{-webkit-appearance:none;-moz-appearance:none;appearance:none}#midconfig input[type=checkbox]{display:none}#midconfig input[type=checkbox]+label{cursor:pointer}#midconfig input[type=checkbox]+label>svg.midconfig-svg-checkmark{width:16px;height:16px;min-width:16px;min-height:16px;margin:2px;border:2px solid var(--text3);border-radius:4px;fill:rgba(0,0,0,0);transition-property:background-color,border}#midconfig input[type=checkbox]:checked+label>svg.midconfig-svg-checkmark{background-color:var(--accent1);border:none;fill:var(--accent-text)}#midconfig .midconfig-select-container{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;position:relative}#midconfig .midconfig-select-container>select{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:100%}#midconfig .midconfig-select-container>select:focus{outline:none}#midconfig .midconfig-select-container>svg.midconfig-svg-arrow-down{position:absolute;top:3px;right:3px;width:24px;height:24px;min-width:24px;min-height:24px}#midconfig .midconfig-button-container{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;width:100%}#midconfig .midconfig-button-container__disable>.midconfig-button,#midconfig .midconfig-button-container.midconfig-button-empty>.midconfig-button{opacity:.25;pointer-events:none}#midconfig .midconfig-button{display:inline-block;width:inherit;height:30px;line-height:30px;text-align:center;background-color:var(--back1);border-radius:8px;cursor:pointer}#midconfig .midconfig-button:hover{filter:opacity(0.7)}#midconfig .midconfig-button:hover:active{filter:opacity(0.5)}#midconfig .midconfig-button--solid{color:var(--accent1)}#midconfig .midconfig-button--outline{line-height:28px;color:var(--accent1);border:1px solid var(--accent1)}#midconfig .midconfig-button--outline:hover{color:var(--accent-text);background-color:var(--accent1);filter:none}#midconfig .midconfig-button--outline:hover:active{filter:opacity(0.7)}#midconfig .midconfig-button--fill-alpha{color:var(--accent1);background-color:var(--accent2)}#midconfig .midconfig-button--fill{color:var(--accent-text);background-color:var(--accent1)}#midconfig .midconfig-button--solid-red{color:var(--red1)}#midconfig .midconfig-button--outline-red{line-height:28px;color:var(--red1);border:1px solid var(--red1)}#midconfig .midconfig-button--outline-red:hover{color:#fff;background-color:var(--red1);filter:none}#midconfig .midconfig-button--outline-red:hover:active{filter:opacity(0.7)}#midconfig .midconfig-button--fill-alpha-red{color:var(--red1);background-color:var(--red2)}#midconfig .midconfig-button--fill-red{color:#fff;background-color:var(--red1)}#midconfig>*{width:100%}#midconfig .midconfig-tab{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;gap:5px;padding:5px 5px 0;border-bottom:1px solid var(--text3)}#midconfig .midconfig-tab>.midconfig-tab-item{display:inline-block;width:inherit;height:30px;line-height:30px;padding:0 0 5px;text-align:center;color:var(--text2);cursor:pointer;box-sizing:content-box}#midconfig .midconfig-tab>.midconfig-tab-item::after{content:"";display:block;position:relative;top:1px;width:100%;height:4px;background-color:var(--accent1);border-radius:2px;opacity:0}#midconfig .midconfig-tab>.midconfig-tab-item__selected{font-weight:600;color:var(--accent1)}#midconfig .midconfig-tab>.midconfig-tab-item__selected::after{opacity:1}#midconfig .midconfig-main{height:100%;padding:10px 8px 10px 10px;overflow-y:scroll}#midconfig .midconfig-main>.midconfig-page-item{display:none}#midconfig .midconfig-main>.midconfig-page-item__selected{display:flex;flex-direction:column;flex-wrap:nowrap;gap:5px}#midconfig .midconfig-main>.midconfig-page-item .midconfig-group>.midconfig-group-header{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;justify-content:space-between;height:30px}#midconfig .midconfig-main>.midconfig-page-item .midconfig-group>.midconfig-group-header>svg.midconfig-svg-arrow-down{width:30px;height:inherit;max-width:30px;max-height:30px;min-width:30px;min-height:30px;transform:scale(-1, -1)}#midconfig .midconfig-main>.midconfig-page-item .midconfig-group>.midconfig-group-items{display:flex;flex-direction:column;flex-wrap:nowrap;gap:5px}#midconfig .midconfig-main>.midconfig-page-item .midconfig-group>.midconfig-group-items>.midconfig-item>.midconfig-label-container{padding-left:15px}#midconfig .midconfig-main>.midconfig-page-item .midconfig-group.midconfig-accordion>.midconfig-group-header{cursor:pointer}#midconfig .midconfig-main>.midconfig-page-item .midconfig-group.midconfig-accordion__close>.midconfig-group-header>svg.midconfig-svg-arrow-down{transform:scale(1, 1)}#midconfig .midconfig-main>.midconfig-page-item .midconfig-group.midconfig-accordion__close>.midconfig-group-items{display:none}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;justify-content:space-between;gap:5px;height:30px;overflow:hidden}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item:not(.midconfig-item-checkbox)>*{width:50%;overflow:hidden}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>*{width:100%;height:inherit}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>*>*{width:100%;height:inherit}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-label-container>label{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;gap:5px}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;gap:5px}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=text]:focus{outline:none;border-color:var(--accent1)}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=color]{width:30px;height:30px;min-width:30px;min-height:30px;border:none;border-radius:50%;overflow:hidden;cursor:pointer}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=color]::-webkit-color-swatch-wrapper{padding:0}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=color]::-moz-color-swatch-wrapper{padding:0}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=color]::-webkit-color-swatch{border:1px solid var(--text3);border-radius:50%}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=color]::-moz-color-swatch{border:1px solid var(--text3);border-radius:50%}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=range]{width:65%;height:6px;background:linear-gradient(90deg, var(--accent1) var(--range-progress, 0), var(--text3) var(--range-progress, 0));border-radius:3px;transition:none}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:12px;height:12px;background-color:var(--accent1);border-radius:6px;border:none;cursor:ew-resize}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=range]::-moz-range-thumb{-moz-appearance:none;appearance:none;width:12px;height:12px;background-color:var(--accent1);border-radius:6px;border:none;cursor:ew-resize}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item>.midconfig-input-container>input[type=range]+input[type=text]{width:35%;padding:0;text-align:center}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item.midconfig-button-container>.midconfig-label-container{width:100%}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item.midconfig-button-container>.midconfig-button{max-width:120px;min-width:90px}#midconfig .midconfig-main>.midconfig-page-item .midconfig-item__disable>.midconfig-input-container{opacity:.25;pointer-events:none}#midconfig .midconfig-main>.midconfig-page-item .midconfig-divider{display:block;width:100%;height:1px;background-color:var(--text3);margin:2px 0}#midconfig .midconfig-bottom{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;gap:5px;padding:5px;border-top:1px solid var(--text3)}';
  847. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/util.ts
  848. const escapeHTML = (html) => {
  849. if (typeof html !== 'string') {
  850. return html;
  851. }
  852. return html.replace(/[&'`"<>]/g, (match) => {
  853. return {
  854. '&': '&amp;',
  855. "'": '&#x27;',
  856. '`': '&#x60;',
  857. '"': '&quot;',
  858. '<': '&lt;',
  859. '>': '&gt;',
  860. }[match] || match;
  861. });
  862. };
  863. const setTextWithTitle = (elem, text) => {
  864. elem.textContent = text;
  865. elem.addEventListener('mouseover', ({ target }) => {
  866. if (target instanceof HTMLElement) {
  867. if (0 < target.scrollWidth - target.offsetWidth) {
  868. target.title = target.textContent || '';
  869. }
  870. else {
  871. target.title = '';
  872. }
  873. }
  874. });
  875. };
  876. const fullWidthToHalfWidth = (str) => {
  877. return str
  878. .replace('#', '#')
  879. .replace(/[a-z0-9]/g, s => String.fromCharCode(s.charCodeAt(0) - 0xFEE0));
  880. };
  881. const generateUID = (len = 10) => {
  882. const str = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`;
  883. return `${Array.from(Array(len)).map(() => str[Math.random() * str.length | 0]).join('')}-${Date.now()}`;
  884. };
  885. const isColorCode = (hex) => {
  886. return /^#?[a-fA-F0-9]{6}$/.test(hex);
  887. };
  888. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/Item.ts
  889. var Item_classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  890. if (kind === "m") throw new TypeError("Private method is not writable");
  891. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  892. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  893. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  894. };
  895. var Item_classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  896. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  897. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  898. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  899. };
  900. var _Item_initData, _Item_uid, _Item_value, _Item_labalContainer, _Item_inputContainer, _Item_inputCheckbox;
  901. class Item_Item extends HTMLElement {
  902. constructor(initData) {
  903. super();
  904. _Item_initData.set(this, void 0);
  905. _Item_uid.set(this, void 0);
  906. _Item_value.set(this, void 0);
  907. _Item_labalContainer.set(this, void 0);
  908. _Item_inputContainer.set(this, void 0);
  909. _Item_inputCheckbox.set(this, null);
  910. Item_classPrivateFieldSet(this, _Item_initData, initData, "f");
  911. Item_classPrivateFieldSet(this, _Item_uid, `midconfig-${generateUID()}`, "f");
  912. Item_classPrivateFieldSet(this, _Item_value, initData.default, "f");
  913. this.classList.add(Item_Item.NAME);
  914. this.classList.add(this.tagName.toLowerCase());
  915. Item_classPrivateFieldSet(this, _Item_labalContainer, document.createElement('div'), "f");
  916. Item_classPrivateFieldGet(this, _Item_labalContainer, "f").classList.add('midconfig-label-container');
  917. // ラベル
  918. const label = document.createElement('label');
  919. const span = document.createElement('span');
  920. setTextWithTitle(span, initData.label);
  921. label.appendChild(span);
  922. Item_classPrivateFieldGet(this, _Item_labalContainer, "f").insertAdjacentElement('beforeend', label);
  923. // チェックボックス
  924. if (initData.withCheckBox === true) {
  925. label.setAttribute('for', Item_classPrivateFieldGet(this, _Item_uid, "f"));
  926. label.insertAdjacentHTML('afterbegin', SVG_CHECKMARK);
  927. Item_classPrivateFieldSet(this, _Item_inputCheckbox, document.createElement('input'), "f");
  928. Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f").type = 'checkbox';
  929. Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f").id = Item_classPrivateFieldGet(this, _Item_uid, "f");
  930. Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f").checked = Boolean(initData.checked);
  931. if (!this.checked) {
  932. this.classList.add(`${Item_Item.NAME}__disable`);
  933. }
  934. Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f").addEventListener('change', () => {
  935. if (this.checked) {
  936. this.classList.remove(`${Item_Item.NAME}__disable`);
  937. }
  938. else {
  939. this.classList.add(`${Item_Item.NAME}__disable`);
  940. }
  941. if (typeof Item_classPrivateFieldGet(this, _Item_initData, "f").onChange === 'function') {
  942. Item_classPrivateFieldGet(this, _Item_initData, "f").onChange({
  943. target: this,
  944. id: Item_classPrivateFieldGet(this, _Item_initData, "f").id,
  945. value: null,
  946. checked: this.checked,
  947. });
  948. }
  949. });
  950. Item_classPrivateFieldGet(this, _Item_labalContainer, "f").insertAdjacentElement('afterbegin', Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f"));
  951. }
  952. Item_classPrivateFieldSet(this, _Item_inputContainer, document.createElement('div'), "f");
  953. Item_classPrivateFieldGet(this, _Item_inputContainer, "f").classList.add('midconfig-input-container');
  954. this.appendChild(Item_classPrivateFieldGet(this, _Item_labalContainer, "f"));
  955. this.appendChild(Item_classPrivateFieldGet(this, _Item_inputContainer, "f"));
  956. }
  957. get initData() { return Item_classPrivateFieldGet(this, _Item_initData, "f"); }
  958. get uid() { return Item_classPrivateFieldGet(this, _Item_uid, "f"); }
  959. get value() { return Item_classPrivateFieldGet(this, _Item_value, "f"); }
  960. get checked() {
  961. if (Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f") !== null) {
  962. return Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f").checked;
  963. }
  964. else {
  965. return null;
  966. }
  967. }
  968. get labalContainer() { return Item_classPrivateFieldGet(this, _Item_labalContainer, "f"); }
  969. get inputContainer() { return Item_classPrivateFieldGet(this, _Item_inputContainer, "f"); }
  970. get inputCheckbox() { return Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f"); }
  971. set checked(data) {
  972. if (typeof data === 'boolean' &&
  973. Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f") !== null) {
  974. if (data === Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f").checked) {
  975. return;
  976. }
  977. Item_classPrivateFieldGet(this, _Item_inputCheckbox, "f").checked = data;
  978. if (this.checked) {
  979. this.classList.remove(`${Item_Item.NAME}__disable`);
  980. }
  981. else {
  982. this.classList.add(`${Item_Item.NAME}__disable`);
  983. }
  984. if (typeof Item_classPrivateFieldGet(this, _Item_initData, "f").onChange === 'function') {
  985. Item_classPrivateFieldGet(this, _Item_initData, "f").onChange({
  986. target: this,
  987. id: Item_classPrivateFieldGet(this, _Item_initData, "f").id,
  988. value: null,
  989. checked: this.checked,
  990. });
  991. }
  992. }
  993. }
  994. set _value(data) {
  995. if (typeof data === 'string' ||
  996. typeof data === 'number' ||
  997. typeof data === 'boolean') {
  998. if (data === Item_classPrivateFieldGet(this, _Item_value, "f")) {
  999. return;
  1000. }
  1001. Item_classPrivateFieldSet(this, _Item_value, data, "f");
  1002. if (typeof Item_classPrivateFieldGet(this, _Item_initData, "f").onChange === 'function') {
  1003. Item_classPrivateFieldGet(this, _Item_initData, "f").onChange({
  1004. target: this,
  1005. id: Item_classPrivateFieldGet(this, _Item_initData, "f").id,
  1006. value: Item_classPrivateFieldGet(this, _Item_value, "f"),
  1007. checked: this.checked,
  1008. });
  1009. }
  1010. }
  1011. }
  1012. getValue() { return this.value; }
  1013. setValue(data) {
  1014. if (typeof data === 'string' ||
  1015. typeof data === 'number' ||
  1016. typeof data === 'boolean') {
  1017. this._value = data;
  1018. }
  1019. }
  1020. getData() {
  1021. return {
  1022. checked: this.checked,
  1023. value: this.value,
  1024. default: Item_classPrivateFieldGet(this, _Item_initData, "f").default,
  1025. };
  1026. }
  1027. setData(data) {
  1028. this.setValue(data.value);
  1029. this.checked = data.checked;
  1030. }
  1031. reset() {
  1032. this.setValue(Item_classPrivateFieldGet(this, _Item_initData, "f").default);
  1033. this.checked = Boolean(Item_classPrivateFieldGet(this, _Item_initData, "f").checked);
  1034. }
  1035. }
  1036. _Item_initData = new WeakMap(), _Item_uid = new WeakMap(), _Item_value = new WeakMap(), _Item_labalContainer = new WeakMap(), _Item_inputContainer = new WeakMap(), _Item_inputCheckbox = new WeakMap();
  1037. Item_Item.NAME = 'midconfig-item';
  1038. // customElements.define(Item.NAME, Item)
  1039. customElements.constructor.prototype.define.call(customElements, Item_Item.NAME, Item_Item);
  1040. /* harmony default export */ var Items_Item = (Item_Item);
  1041. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/Text.ts
  1042. var Text_classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  1043. if (kind === "m") throw new TypeError("Private method is not writable");
  1044. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  1045. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  1046. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  1047. };
  1048. var Text_classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  1049. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  1050. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  1051. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  1052. };
  1053. var _Text_inputText;
  1054. class Text extends Items_Item {
  1055. constructor(initData, option) {
  1056. super(initData);
  1057. _Text_inputText.set(this, void 0);
  1058. Text_classPrivateFieldSet(this, _Text_inputText, document.createElement('input'), "f");
  1059. Text_classPrivateFieldGet(this, _Text_inputText, "f").type = 'text';
  1060. Text_classPrivateFieldGet(this, _Text_inputText, "f").value = initData.default;
  1061. Text_classPrivateFieldGet(this, _Text_inputText, "f").spellcheck = false;
  1062. Text_classPrivateFieldGet(this, _Text_inputText, "f").setAttribute('autocorrect', 'off');
  1063. if (typeof option?.maxlength === 'number') {
  1064. Text_classPrivateFieldGet(this, _Text_inputText, "f").maxLength = option.maxlength;
  1065. }
  1066. if (typeof option?.minlength === 'number') {
  1067. Text_classPrivateFieldGet(this, _Text_inputText, "f").minLength = option.minlength;
  1068. }
  1069. if (typeof option?.placeholder === 'string') {
  1070. Text_classPrivateFieldGet(this, _Text_inputText, "f").placeholder = option.placeholder;
  1071. }
  1072. else {
  1073. Text_classPrivateFieldGet(this, _Text_inputText, "f").placeholder = initData.default;
  1074. }
  1075. Text_classPrivateFieldGet(this, _Text_inputText, "f").addEventListener('change', () => {
  1076. this.setValue(Text_classPrivateFieldGet(this, _Text_inputText, "f").value);
  1077. });
  1078. this.inputContainer.appendChild(Text_classPrivateFieldGet(this, _Text_inputText, "f"));
  1079. }
  1080. setValue(data) {
  1081. if (typeof data === 'number') {
  1082. data = data.toString();
  1083. }
  1084. if (typeof data === 'string') {
  1085. data = data.trim();
  1086. Text_classPrivateFieldGet(this, _Text_inputText, "f").value = data;
  1087. this._value = data;
  1088. }
  1089. }
  1090. }
  1091. _Text_inputText = new WeakMap();
  1092. // customElements.define('midconfig-item-text', Text)
  1093. customElements.constructor.prototype.define.call(customElements, 'midconfig-item-text', Text);
  1094. /* harmony default export */ var Items_Text = ((/* unused pure expression or super */ null && (Text)));
  1095. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/CheckBox.ts
  1096. class CheckBox extends Items_Item {
  1097. constructor(initData) {
  1098. initData.withCheckBox = true;
  1099. initData.checked || (initData.checked = initData.default);
  1100. super(initData);
  1101. this.inputContainer.remove();
  1102. }
  1103. get value() { return Boolean(this.inputCheckbox?.checked); }
  1104. setValue(data) {
  1105. if (typeof data === 'boolean' &&
  1106. this.inputCheckbox !== null) {
  1107. this.inputCheckbox.checked = data;
  1108. this._value = data;
  1109. }
  1110. }
  1111. }
  1112. // customElements.define('midconfig-item-checkbox', CheckBox)
  1113. customElements.constructor.prototype.define.call(customElements, 'midconfig-item-checkbox', CheckBox);
  1114. /* harmony default export */ var Items_CheckBox = (CheckBox);
  1115. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/Color.ts
  1116. var Color_classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  1117. if (kind === "m") throw new TypeError("Private method is not writable");
  1118. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  1119. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  1120. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  1121. };
  1122. var Color_classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  1123. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  1124. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  1125. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  1126. };
  1127. var _Color_inputColor, _Color_inputText;
  1128. class Color extends Items_Item {
  1129. constructor(initData, option) {
  1130. super(initData);
  1131. _Color_inputColor.set(this, void 0);
  1132. _Color_inputText.set(this, void 0);
  1133. initData.default = initData.default.toUpperCase();
  1134. Color_classPrivateFieldSet(this, _Color_inputColor, document.createElement('input'), "f");
  1135. Color_classPrivateFieldGet(this, _Color_inputColor, "f").type = 'color';
  1136. Color_classPrivateFieldGet(this, _Color_inputColor, "f").value = initData.default;
  1137. Color_classPrivateFieldSet(this, _Color_inputText, document.createElement('input'), "f");
  1138. Color_classPrivateFieldGet(this, _Color_inputText, "f").type = 'text';
  1139. Color_classPrivateFieldGet(this, _Color_inputText, "f").value = initData.default;
  1140. Color_classPrivateFieldGet(this, _Color_inputText, "f").spellcheck = false;
  1141. Color_classPrivateFieldGet(this, _Color_inputText, "f").setAttribute('autocorrect', 'off');
  1142. Color_classPrivateFieldGet(this, _Color_inputText, "f").maxLength = 7;
  1143. Color_classPrivateFieldGet(this, _Color_inputText, "f").minLength = 6;
  1144. if (typeof option?.placeholder === 'string') {
  1145. Color_classPrivateFieldGet(this, _Color_inputText, "f").placeholder = option.placeholder;
  1146. }
  1147. else {
  1148. Color_classPrivateFieldGet(this, _Color_inputText, "f").placeholder = initData.default;
  1149. }
  1150. const changeHandler = ({ target }) => {
  1151. if (target instanceof HTMLInputElement) {
  1152. if (target.value === '') {
  1153. target.value = this.initData.default;
  1154. }
  1155. target.value = fullWidthToHalfWidth(target.value);
  1156. this.setValue(target.value);
  1157. }
  1158. };
  1159. Color_classPrivateFieldGet(this, _Color_inputColor, "f").addEventListener('change', changeHandler);
  1160. Color_classPrivateFieldGet(this, _Color_inputText, "f").addEventListener('change', changeHandler);
  1161. this.inputContainer.appendChild(Color_classPrivateFieldGet(this, _Color_inputColor, "f"));
  1162. this.inputContainer.appendChild(Color_classPrivateFieldGet(this, _Color_inputText, "f"));
  1163. }
  1164. setValue(data) {
  1165. if (typeof data === 'string') {
  1166. data = data.trim().toUpperCase();
  1167. if (!isColorCode(data)) {
  1168. data = this.initData.default;
  1169. }
  1170. if (!data.startsWith('#')) {
  1171. data = `#${data}`;
  1172. }
  1173. Color_classPrivateFieldGet(this, _Color_inputColor, "f").value = data;
  1174. Color_classPrivateFieldGet(this, _Color_inputText, "f").value = data;
  1175. this._value = data;
  1176. }
  1177. }
  1178. }
  1179. _Color_inputColor = new WeakMap(), _Color_inputText = new WeakMap();
  1180. // customElements.define('midconfig-item-color', Color)
  1181. customElements.constructor.prototype.define.call(customElements, 'midconfig-item-color', Color);
  1182. /* harmony default export */ var Items_Color = (Color);
  1183. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/Range.ts
  1184. var Range_classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  1185. if (kind === "m") throw new TypeError("Private method is not writable");
  1186. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  1187. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  1188. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  1189. };
  1190. var Range_classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  1191. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  1192. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  1193. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  1194. };
  1195. var _Range_inputRange, _Range_inputText;
  1196. class Range extends Items_Item {
  1197. constructor(initData, option) {
  1198. super(initData);
  1199. _Range_inputRange.set(this, void 0);
  1200. _Range_inputText.set(this, void 0);
  1201. Range_classPrivateFieldSet(this, _Range_inputRange, document.createElement('input'), "f");
  1202. Range_classPrivateFieldGet(this, _Range_inputRange, "f").type = 'range';
  1203. Range_classPrivateFieldGet(this, _Range_inputRange, "f").value = initData.default.toString();
  1204. Range_classPrivateFieldGet(this, _Range_inputRange, "f").max = option.max.toString();
  1205. Range_classPrivateFieldGet(this, _Range_inputRange, "f").min = option.min.toString();
  1206. Range_classPrivateFieldGet(this, _Range_inputRange, "f").step = option.step.toString();
  1207. Range_classPrivateFieldGet(this, _Range_inputRange, "f").style.setProperty('--range-progress', `${(initData.default - option.min) / (option.max - option.min) * 100}%`);
  1208. Range_classPrivateFieldSet(this, _Range_inputText, document.createElement('input'), "f");
  1209. Range_classPrivateFieldGet(this, _Range_inputText, "f").type = 'text';
  1210. Range_classPrivateFieldGet(this, _Range_inputText, "f").value = initData.default.toString();
  1211. Range_classPrivateFieldGet(this, _Range_inputText, "f").spellcheck = false;
  1212. Range_classPrivateFieldGet(this, _Range_inputText, "f").setAttribute('autocorrect', 'off');
  1213. Range_classPrivateFieldGet(this, _Range_inputText, "f").maxLength = (option.max + option.step).toString().length;
  1214. if (typeof option.placeholder === 'string') {
  1215. Range_classPrivateFieldGet(this, _Range_inputText, "f").placeholder = option.placeholder;
  1216. }
  1217. else {
  1218. Range_classPrivateFieldGet(this, _Range_inputText, "f").placeholder = initData.default.toString();
  1219. }
  1220. Range_classPrivateFieldGet(this, _Range_inputRange, "f").addEventListener('input', () => {
  1221. Range_classPrivateFieldGet(this, _Range_inputRange, "f").style.setProperty('--range-progress', `${(Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").value) - Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").min)) / (Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").max) - Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").min)) * 100}%`);
  1222. Range_classPrivateFieldGet(this, _Range_inputText, "f").value = Range_classPrivateFieldGet(this, _Range_inputRange, "f").value;
  1223. });
  1224. const changeHandler = ({ target }) => {
  1225. if (target instanceof HTMLInputElement) {
  1226. if (target.value === '') {
  1227. target.value = this.initData.default;
  1228. }
  1229. target.value = fullWidthToHalfWidth(target.value);
  1230. this.setValue(target.value);
  1231. }
  1232. };
  1233. Range_classPrivateFieldGet(this, _Range_inputRange, "f").addEventListener('change', changeHandler);
  1234. Range_classPrivateFieldGet(this, _Range_inputText, "f").addEventListener('change', changeHandler);
  1235. this.inputContainer.appendChild(Range_classPrivateFieldGet(this, _Range_inputRange, "f"));
  1236. this.inputContainer.appendChild(Range_classPrivateFieldGet(this, _Range_inputText, "f"));
  1237. }
  1238. setValue(data) {
  1239. if (typeof data === 'string') {
  1240. data = Number(data);
  1241. }
  1242. if (Number.isNaN(data)) {
  1243. data = this.initData.default;
  1244. }
  1245. if (typeof data === 'number' &&
  1246. data <= Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").max) &&
  1247. Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").min) <= data) {
  1248. Range_classPrivateFieldGet(this, _Range_inputRange, "f").value = data.toString();
  1249. Range_classPrivateFieldGet(this, _Range_inputText, "f").value = data.toString();
  1250. Range_classPrivateFieldGet(this, _Range_inputRange, "f").style.setProperty('--range-progress', `${(Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").value) - Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").min)) / (Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").max) - Number(Range_classPrivateFieldGet(this, _Range_inputRange, "f").min)) * 100}%`);
  1251. this._value = data;
  1252. }
  1253. }
  1254. }
  1255. _Range_inputRange = new WeakMap(), _Range_inputText = new WeakMap();
  1256. // customElements.define('midconfig-item-range', Range)
  1257. customElements.constructor.prototype.define.call(customElements, 'midconfig-item-range', Range);
  1258. /* harmony default export */ var Items_Range = (Range);
  1259. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/Select.ts
  1260. var Select_classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  1261. if (kind === "m") throw new TypeError("Private method is not writable");
  1262. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  1263. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  1264. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  1265. };
  1266. var Select_classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  1267. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  1268. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  1269. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  1270. };
  1271. var _Select_select, _Select_options;
  1272. class Select extends Items_Item {
  1273. constructor(initData, options) {
  1274. super(initData);
  1275. _Select_select.set(this, void 0);
  1276. _Select_options.set(this, []);
  1277. const selectContainer = document.createElement('div');
  1278. selectContainer.classList.add('midconfig-select-container');
  1279. Select_classPrivateFieldSet(this, _Select_select, document.createElement('select'), "f");
  1280. for (const { text, value } of options) {
  1281. const option = document.createElement('option');
  1282. option.text = text;
  1283. option.value = value;
  1284. if (value === initData.default) {
  1285. option.selected = true;
  1286. }
  1287. Select_classPrivateFieldGet(this, _Select_select, "f").appendChild(option);
  1288. Select_classPrivateFieldGet(this, _Select_options, "f").push(option);
  1289. }
  1290. Select_classPrivateFieldGet(this, _Select_select, "f").addEventListener('change', () => {
  1291. this.setValue(Select_classPrivateFieldGet(this, _Select_select, "f").value);
  1292. });
  1293. selectContainer.appendChild(Select_classPrivateFieldGet(this, _Select_select, "f"));
  1294. selectContainer.insertAdjacentHTML('beforeend', SVG_ARROW_DOWN);
  1295. this.inputContainer.appendChild(selectContainer);
  1296. }
  1297. setValue(data) {
  1298. if (typeof data === 'string') {
  1299. data = data.trim();
  1300. const targetOption = Select_classPrivateFieldGet(this, _Select_options, "f").find(v => v.value === data);
  1301. if (targetOption !== void 0) {
  1302. targetOption.selected = true;
  1303. this._value = data;
  1304. }
  1305. }
  1306. }
  1307. }
  1308. _Select_select = new WeakMap(), _Select_options = new WeakMap();
  1309. // customElements.define('midconfig-item-select', Select)
  1310. customElements.constructor.prototype.define.call(customElements, 'midconfig-item-select', Select);
  1311. /* harmony default export */ var Items_Select = (Select);
  1312. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/Button.ts
  1313. var Button_classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  1314. if (kind === "m") throw new TypeError("Private method is not writable");
  1315. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  1316. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  1317. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  1318. };
  1319. var Button_classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  1320. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  1321. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  1322. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  1323. };
  1324. var _Button_initData, _Button_disable, _Button_labalContainer;
  1325. class Button extends HTMLElement {
  1326. constructor(initData) {
  1327. super();
  1328. _Button_initData.set(this, void 0);
  1329. _Button_disable.set(this, void 0);
  1330. _Button_labalContainer.set(this, null);
  1331. Button_classPrivateFieldSet(this, _Button_initData, initData, "f");
  1332. this.disable = Boolean(initData.disable);
  1333. this.classList.add('midconfig-item');
  1334. this.classList.add(this.tagName.toLowerCase());
  1335. if (typeof initData.label === 'string') {
  1336. Button_classPrivateFieldSet(this, _Button_labalContainer, document.createElement('div'), "f");
  1337. Button_classPrivateFieldGet(this, _Button_labalContainer, "f").classList.add('midconfig-label-container');
  1338. const label = document.createElement('label');
  1339. const span = document.createElement('span');
  1340. setTextWithTitle(span, initData.label);
  1341. label.appendChild(span);
  1342. Button_classPrivateFieldGet(this, _Button_labalContainer, "f").appendChild(label);
  1343. this.appendChild(Button_classPrivateFieldGet(this, _Button_labalContainer, "f"));
  1344. }
  1345. const button = document.createElement('div');
  1346. button.classList.add('midconfig-button');
  1347. button.classList.add(`midconfig-button--${initData.type}`);
  1348. setTextWithTitle(button, initData.text);
  1349. button.addEventListener('click', () => {
  1350. Button_classPrivateFieldGet(this, _Button_initData, "f").onClick(Button_classPrivateFieldGet(this, _Button_initData, "f").id);
  1351. });
  1352. this.appendChild(button);
  1353. }
  1354. get initData() { return Button_classPrivateFieldGet(this, _Button_initData, "f"); }
  1355. get disable() { return Button_classPrivateFieldGet(this, _Button_disable, "f"); }
  1356. get labalContainer() { return Button_classPrivateFieldGet(this, _Button_labalContainer, "f"); }
  1357. set disable(v) {
  1358. Button_classPrivateFieldSet(this, _Button_disable, Boolean(v), "f");
  1359. if (Button_classPrivateFieldGet(this, _Button_disable, "f")) {
  1360. this.classList.add(`${Button.NAME}__disable`);
  1361. }
  1362. else {
  1363. this.classList.remove(`${Button.NAME}__disable`);
  1364. }
  1365. }
  1366. }
  1367. _Button_initData = new WeakMap(), _Button_disable = new WeakMap(), _Button_labalContainer = new WeakMap();
  1368. Button.NAME = 'midconfig-button-container';
  1369. // customElements.define(Button.NAME, Button)
  1370. customElements.constructor.prototype.define.call(customElements, Button.NAME, Button);
  1371. /* harmony default export */ var Items_Button = (Button);
  1372. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/ButtonEmpty.ts
  1373. class ButtonEmpty extends Items_Button {
  1374. constructor() {
  1375. super({
  1376. id: '',
  1377. text: '',
  1378. type: 'solid',
  1379. // disable: true,
  1380. onClick: () => null,
  1381. });
  1382. this.classList.add('midconfig-button-container');
  1383. }
  1384. }
  1385. ButtonEmpty.NAME = 'midconfig-button-empty';
  1386. // customElements.define(ButtonEmpty.NAME, ButtonEmpty)
  1387. customElements.constructor.prototype.define.call(customElements, ButtonEmpty.NAME, ButtonEmpty);
  1388. /* harmony default export */ var Items_ButtonEmpty = (ButtonEmpty);
  1389. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/Divider.ts
  1390. class Divider extends HTMLElement {
  1391. constructor() {
  1392. super();
  1393. this.classList.add(this.tagName.toLowerCase());
  1394. }
  1395. }
  1396. Divider.NAME = 'midconfig-divider';
  1397. // customElements.define(Divider.NAME, Divider)
  1398. customElements.constructor.prototype.define.call(customElements, Divider.NAME, Divider);
  1399. /* harmony default export */ var Items_Divider = ((/* unused pure expression or super */ null && (Divider)));
  1400. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/Group.ts
  1401. var Group_classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  1402. if (kind === "m") throw new TypeError("Private method is not writable");
  1403. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  1404. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  1405. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  1406. };
  1407. var Group_classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  1408. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  1409. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  1410. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  1411. };
  1412. var _Group_initData, _Group_isOpen;
  1413. class Group extends HTMLElement {
  1414. constructor(initData) {
  1415. super();
  1416. _Group_initData.set(this, void 0);
  1417. _Group_isOpen.set(this, void 0);
  1418. Group_classPrivateFieldSet(this, _Group_initData, initData, "f");
  1419. Group_classPrivateFieldSet(this, _Group_isOpen, Boolean(initData.isAccordionOpen), "f");
  1420. this.classList.add(Group.NAME);
  1421. // ヘッダー
  1422. const header = document.createElement('div');
  1423. header.classList.add(`${Group.NAME}-header`);
  1424. const span = document.createElement('span');
  1425. setTextWithTitle(span, initData.label);
  1426. header.appendChild(span);
  1427. // アイテム
  1428. const items = document.createElement('div');
  1429. items.classList.add(`${Group.NAME}-items`);
  1430. for (const item of initData.items) {
  1431. items.appendChild(item);
  1432. }
  1433. if (initData.isAccordion) {
  1434. this.classList.add('midconfig-accordion');
  1435. if (!Group_classPrivateFieldGet(this, _Group_isOpen, "f")) {
  1436. this.classList.add('midconfig-accordion__close');
  1437. }
  1438. header.insertAdjacentHTML('beforeend', SVG_ARROW_DOWN);
  1439. header.addEventListener('click', () => Group_classPrivateFieldGet(this, _Group_isOpen, "f") ? this.close() : this.open());
  1440. }
  1441. this.appendChild(header);
  1442. this.appendChild(items);
  1443. }
  1444. get initData() { return Group_classPrivateFieldGet(this, _Group_initData, "f"); }
  1445. get isOpen() { return Group_classPrivateFieldGet(this, _Group_isOpen, "f"); }
  1446. open() {
  1447. Group_classPrivateFieldSet(this, _Group_isOpen, true, "f");
  1448. this.classList.remove('midconfig-accordion__close');
  1449. }
  1450. close() {
  1451. Group_classPrivateFieldSet(this, _Group_isOpen, false, "f");
  1452. this.classList.add('midconfig-accordion__close');
  1453. }
  1454. getData() {
  1455. const data = {};
  1456. Group_classPrivateFieldGet(this, _Group_initData, "f").items.forEach(item => {
  1457. if (item instanceof Items_Item) {
  1458. data[item.initData.id] = item.getData();
  1459. }
  1460. });
  1461. return data;
  1462. }
  1463. setData(values) {
  1464. Object.keys(values).forEach(id => {
  1465. Group_classPrivateFieldGet(this, _Group_initData, "f").items.forEach(item => {
  1466. if (item instanceof Items_Item &&
  1467. item.initData.id === id) {
  1468. item.setData(values[id]);
  1469. }
  1470. });
  1471. });
  1472. }
  1473. reset() {
  1474. Group_classPrivateFieldGet(this, _Group_initData, "f").items.forEach(v => v instanceof Items_Item && v.reset());
  1475. }
  1476. }
  1477. _Group_initData = new WeakMap(), _Group_isOpen = new WeakMap();
  1478. Group.NAME = 'midconfig-group';
  1479. // customElements.define(Group.NAME, Group)
  1480. customElements.constructor.prototype.define.call(customElements, Group.NAME, Group);
  1481. /* harmony default export */ var Items_Group = (Group);
  1482. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/Items/index.ts
  1483. // import TextArea from './TextArea'
  1484. ;// CONCATENATED MODULE: ../../Library/MidConfig/src/index.ts
  1485. var src_classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
  1486. if (kind === "m") throw new TypeError("Private method is not writable");
  1487. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
  1488. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
  1489. return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
  1490. };
  1491. var src_classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
  1492. if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
  1493. if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
  1494. return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
  1495. };
  1496. var _Panel_initData, _Panel_shadowInner, _Panel_tab, _Panel_main, _Panel_bottom;
  1497. class Panel extends HTMLElement {
  1498. constructor(initData, isDev) {
  1499. super();
  1500. _Panel_initData.set(this, void 0);
  1501. _Panel_shadowInner.set(this, null);
  1502. _Panel_tab.set(this, void 0);
  1503. _Panel_main.set(this, void 0);
  1504. _Panel_bottom.set(this, void 0);
  1505. src_classPrivateFieldSet(this, _Panel_initData, initData, "f");
  1506. this.classList.add(Panel.NAME);
  1507. src_classPrivateFieldSet(this, _Panel_tab, document.createElement('div'), "f");
  1508. src_classPrivateFieldGet(this, _Panel_tab, "f").classList.add('midconfig-tab');
  1509. src_classPrivateFieldSet(this, _Panel_main, document.createElement('div'), "f");
  1510. src_classPrivateFieldGet(this, _Panel_main, "f").classList.add('midconfig-main');
  1511. src_classPrivateFieldSet(this, _Panel_bottom, document.createElement('div'), "f");
  1512. src_classPrivateFieldGet(this, _Panel_bottom, "f").classList.add('midconfig-bottom');
  1513. initData.tabs.forEach((tab, idx) => {
  1514. const tabItem = document.createElement('div');
  1515. tabItem.classList.add('midconfig-tab-item');
  1516. setTextWithTitle(tabItem, tab.label);
  1517. const pageItem = document.createElement('div');
  1518. pageItem.classList.add('midconfig-page-item');
  1519. tab.child.forEach(item => pageItem.appendChild(item));
  1520. if (idx === 0) {
  1521. tabItem.classList.add('midconfig-tab-item__selected');
  1522. pageItem.classList.add('midconfig-page-item__selected');
  1523. }
  1524. tabItem.addEventListener('click', () => {
  1525. Array.from(src_classPrivateFieldGet(this, _Panel_tab, "f").children).forEach(item => {
  1526. item.classList.remove('midconfig-tab-item__selected');
  1527. });
  1528. tabItem.classList.add('midconfig-tab-item__selected');
  1529. Array.from(src_classPrivateFieldGet(this, _Panel_main, "f").children).forEach(page => {
  1530. page.classList.remove('midconfig-page-item__selected');
  1531. });
  1532. pageItem.classList.add('midconfig-page-item__selected');
  1533. });
  1534. src_classPrivateFieldGet(this, _Panel_tab, "f").appendChild(tabItem);
  1535. src_classPrivateFieldGet(this, _Panel_main, "f").appendChild(pageItem);
  1536. });
  1537. initData.buttons.forEach(button => {
  1538. delete button.initData.label;
  1539. button.labalContainer?.remove();
  1540. src_classPrivateFieldGet(this, _Panel_bottom, "f").appendChild(button);
  1541. });
  1542. if (!Boolean(isDev)) {
  1543. src_classPrivateFieldSet(this, _Panel_shadowInner, document.createElement('div'), "f");
  1544. src_classPrivateFieldGet(this, _Panel_shadowInner, "f").id = 'midconfig';
  1545. src_classPrivateFieldGet(this, _Panel_shadowInner, "f").appendChild(src_classPrivateFieldGet(this, _Panel_tab, "f"));
  1546. src_classPrivateFieldGet(this, _Panel_shadowInner, "f").appendChild(src_classPrivateFieldGet(this, _Panel_main, "f"));
  1547. src_classPrivateFieldGet(this, _Panel_shadowInner, "f").appendChild(src_classPrivateFieldGet(this, _Panel_bottom, "f"));
  1548. const shadow = this.attachShadow({ mode: 'closed' });
  1549. shadow.appendChild(src_classPrivateFieldGet(this, _Panel_shadowInner, "f"));
  1550. const style = document.createElement('style');
  1551. style.textContent = STYLE;
  1552. shadow.appendChild(style);
  1553. }
  1554. else {
  1555. this.id = 'midconfig';
  1556. this.appendChild(src_classPrivateFieldGet(this, _Panel_tab, "f"));
  1557. this.appendChild(src_classPrivateFieldGet(this, _Panel_main, "f"));
  1558. this.appendChild(src_classPrivateFieldGet(this, _Panel_bottom, "f"));
  1559. }
  1560. this.style.display = isDev ? 'flex' : 'block';
  1561. this.setTheme(initData.theme);
  1562. this.load();
  1563. }
  1564. get initData() { return src_classPrivateFieldGet(this, _Panel_initData, "f"); }
  1565. get key() { return `midconfig-${src_classPrivateFieldGet(this, _Panel_initData, "f").id}`; }
  1566. getJSON() {
  1567. const json = {
  1568. version: src_classPrivateFieldGet(this, _Panel_initData, "f").version,
  1569. data: {},
  1570. };
  1571. src_classPrivateFieldGet(this, _Panel_initData, "f").tabs.forEach(tab => {
  1572. var _a, _b;
  1573. (_a = json.data)[_b = tab.id] || (_a[_b] = {});
  1574. tab.child.forEach(item => {
  1575. if (item instanceof Items_Item ||
  1576. item instanceof Items_Group) {
  1577. json.data[tab.id][item.initData.id] = item.getData();
  1578. }
  1579. });
  1580. });
  1581. return json;
  1582. }
  1583. setJSON(json) {
  1584. if (!isConfigJsonData(json)) {
  1585. return false;
  1586. }
  1587. try {
  1588. Object.keys(json.data).forEach(tabId => {
  1589. const targetTab = src_classPrivateFieldGet(this, _Panel_initData, "f").tabs.filter(v => v.id === tabId);
  1590. targetTab.forEach(tab => {
  1591. Object.keys(json.data[tabId]).forEach(itemId => {
  1592. const data = json.data[tabId][itemId];
  1593. const targetItem = tab.child.filter(item => {
  1594. if (item instanceof Items_Item ||
  1595. item instanceof Items_Group) {
  1596. return item.initData.id === itemId;
  1597. }
  1598. });
  1599. targetItem.forEach(item => {
  1600. if (isConfigItemData(data)) {
  1601. if (item instanceof Items_Item) {
  1602. item.setData(data);
  1603. }
  1604. }
  1605. else {
  1606. if (item instanceof Items_Group) {
  1607. item.setData(data);
  1608. }
  1609. }
  1610. });
  1611. });
  1612. });
  1613. });
  1614. return true;
  1615. }
  1616. catch (e) {
  1617. console.error(e);
  1618. }
  1619. return false;
  1620. }
  1621. save() {
  1622. try {
  1623. const value = JSON.stringify(this.getJSON());
  1624. Panel.setValue(this.key, value);
  1625. }
  1626. catch (e) {
  1627. console.error(e);
  1628. }
  1629. }
  1630. load() {
  1631. try {
  1632. const value = Panel.getValue(this.key);
  1633. if (typeof value === 'string') {
  1634. this.setJSON(JSON.parse(value));
  1635. }
  1636. }
  1637. catch (e) {
  1638. console.error(e);
  1639. }
  1640. }
  1641. reset() {
  1642. src_classPrivateFieldGet(this, _Panel_initData, "f").tabs.forEach(tab => {
  1643. tab.child.forEach(item => {
  1644. if (item instanceof Items_Item ||
  1645. item instanceof Items_Group) {
  1646. item.reset();
  1647. }
  1648. });
  1649. });
  1650. Panel.deleteValue(this.key);
  1651. }
  1652. export() {
  1653. const value = JSON.stringify(this.getJSON());
  1654. window.prompt('エクスポート', value);
  1655. }
  1656. setTheme(theme = 'auto') {
  1657. if (['auto', 'light', 'dark'].includes(theme)) {
  1658. (src_classPrivateFieldGet(this, _Panel_shadowInner, "f") || this).setAttribute('theme', theme);
  1659. }
  1660. }
  1661. static getValue(key) {
  1662. let r###lt;
  1663. let GMGetValue = null;
  1664. try {
  1665. // @ts-ignore
  1666. GMGetValue || (GMGetValue = GM_getValue);
  1667. }
  1668. catch { }
  1669. try {
  1670. // @ts-ignore
  1671. GMGetValue || (GMGetValue = GM && GM.getValue);
  1672. }
  1673. catch { }
  1674. try {
  1675. if (typeof GMGetValue === 'function') {
  1676. r###lt = GMGetValue(key);
  1677. }
  1678. else {
  1679. r###lt = window.localStorage.getItem(key);
  1680. }
  1681. }
  1682. catch (e) {
  1683. console.error(e);
  1684. }
  1685. return r###lt;
  1686. }
  1687. static setValue(key, value) {
  1688. let GMSetValue = null;
  1689. try {
  1690. // @ts-ignore
  1691. GMSetValue || (GMSetValue = GM_setValue);
  1692. }
  1693. catch { }
  1694. try {
  1695. // @ts-ignore
  1696. GMSetValue || (GMSetValue = GM && GM.setValue);
  1697. }
  1698. catch { }
  1699. try {
  1700. if (typeof GMSetValue === 'function') {
  1701. GMSetValue(key, value);
  1702. }
  1703. else {
  1704. window.localStorage.setItem(key, value);
  1705. }
  1706. }
  1707. catch (e) {
  1708. console.error(e);
  1709. }
  1710. }
  1711. static deleteValue(key) {
  1712. let GMDeleteValue = null;
  1713. try {
  1714. // @ts-ignore
  1715. GMDeleteValue || (GMDeleteValue = GM_deleteValue);
  1716. }
  1717. catch { }
  1718. try {
  1719. // @ts-ignore
  1720. GMDeleteValue || (GMDeleteValue = GM && GM.deleteValue);
  1721. }
  1722. catch { }
  1723. try {
  1724. if (typeof GMDeleteValue === 'function') {
  1725. GMDeleteValue(key);
  1726. }
  1727. else {
  1728. window.localStorage.removeItem(key);
  1729. }
  1730. }
  1731. catch (e) {
  1732. console.error(e);
  1733. }
  1734. }
  1735. }
  1736. _Panel_initData = new WeakMap(), _Panel_shadowInner = new WeakMap(), _Panel_tab = new WeakMap(), _Panel_main = new WeakMap(), _Panel_bottom = new WeakMap();
  1737. Panel.NAME = 'midconfig-panel';
  1738. // customElements.define(Panel.NAME, Panel)
  1739. customElements.constructor.prototype.define.call(customElements, Panel.NAME, Panel);
  1740. ;// CONCATENATED MODULE: ./src/config.ts
  1741. /****************************************
  1742. * コメント設定のテンプレート
  1743. */
  1744. const commentConfigTemplate = (options) => {
  1745. options = {
  1746. ...{
  1747. color: '#FFFFFF',
  1748. fontScale: 100,
  1749. fontWeight: '600',
  1750. shadowColor: '#000000',
  1751. opacity: 100,
  1752. },
  1753. ...options,
  1754. };
  1755. return [
  1756. new Items_Color({
  1757. id: 'color',
  1758. label: '色 (Hex)',
  1759. default: options.color,
  1760. withCheckBox: true,
  1761. }),
  1762. new Items_Range({
  1763. id: 'fontScale',
  1764. label: 'サイズ (%)',
  1765. default: options.fontScale,
  1766. withCheckBox: true,
  1767. }, {
  1768. max: 150,
  1769. min: 50,
  1770. step: 10,
  1771. }),
  1772. new Items_Select({
  1773. id: 'fontWeight',
  1774. label: '太さ',
  1775. default: options.fontWeight,
  1776. withCheckBox: true,
  1777. }, [
  1778. { text: '太い', value: '800' },
  1779. { text: '普通', value: '600' },
  1780. { text: '細い', value: '400' },
  1781. ]),
  1782. new Items_Color({
  1783. id: 'shadowColor',
  1784. label: '影の色 (Hex)',
  1785. default: options.shadowColor,
  1786. withCheckBox: true,
  1787. }),
  1788. new Items_Range({
  1789. id: 'opacity',
  1790. label: '不透明度 (%)',
  1791. default: options.opacity,
  1792. withCheckBox: true,
  1793. }, {
  1794. max: 100,
  1795. min: 10,
  1796. step: 10,
  1797. }),
  1798. ];
  1799. };
  1800. /****************************************
  1801. * MidConfigの初期化
  1802. */
  1803. const useConfig = (configData, handlers) => {
  1804. const config = new Panel({
  1805. id: 'flowcomments-for-youtube',
  1806. version: 1,
  1807. theme: document.documentElement.getAttribute('dark') !== null ? 'dark' : 'light',
  1808. tabs: [
  1809. {
  1810. id: 'general',
  1811. label: '全般',
  1812. child: [
  1813. new Items_Select({
  1814. id: 'resolution',
  1815. label: '解像度',
  1816. default: 'auto',
  1817. }, [
  1818. { text: '自動', value: 'auto' },
  1819. { text: '1080p', value: 'r_1080' },
  1820. { text: '720p', value: 'r_720' },
  1821. { text: '480p', value: 'r_480' },
  1822. { text: '360p', value: 'r_360' },
  1823. ]),
  1824. new Items_Range({
  1825. id: 'line',
  1826. label: '行数',
  1827. default: 11,
  1828. }, {
  1829. max: 50,
  1830. min: 1,
  1831. step: 1,
  1832. }),
  1833. new Items_CheckBox({
  1834. id: 'smoothRender',
  1835. label: 'カクつきを抑える (高負荷)',
  1836. default: false,
  1837. }),
  1838. ],
  1839. },
  1840. {
  1841. id: 'comments',
  1842. label: 'コメント',
  1843. child: [
  1844. new Items_Group({
  1845. id: 'default',
  1846. label: 'デフォルト',
  1847. isAccordion: true,
  1848. items: commentConfigTemplate({ color: COLOR.USER }),
  1849. }),
  1850. new Items_Group({
  1851. id: 'member',
  1852. label: 'メンバー',
  1853. isAccordion: true,
  1854. items: commentConfigTemplate({ color: COLOR.MEMBER }),
  1855. }),
  1856. new Items_Group({
  1857. id: 'moderator',
  1858. label: 'モデレーター',
  1859. isAccordion: true,
  1860. items: commentConfigTemplate({ color: COLOR.MODERATOR }),
  1861. }),
  1862. new Items_Group({
  1863. id: 'owner',
  1864. label: 'チャンネル',
  1865. isAccordion: true,
  1866. items: commentConfigTemplate({ color: COLOR.OWNER }),
  1867. }),
  1868. ],
  1869. },
  1870. {
  1871. id: 'filter',
  1872. label: 'フィルタ',
  1873. child: [
  1874. new Items_Group({
  1875. id: 'comments',
  1876. label: '表示するコメント',
  1877. isAccordion: true,
  1878. items: [
  1879. new Items_CheckBox({
  1880. id: 'normal',
  1881. label: '通常',
  1882. default: true,
  1883. }),
  1884. new Items_CheckBox({
  1885. id: 'member',
  1886. label: 'メンバー',
  1887. default: true,
  1888. }),
  1889. new Items_CheckBox({
  1890. id: 'moderator',
  1891. label: 'モデレーター',
  1892. default: true,
  1893. }),
  1894. new Items_CheckBox({
  1895. id: 'owner',
  1896. label: 'チャンネル',
  1897. default: true,
  1898. }),
  1899. new Items_CheckBox({
  1900. id: 'paid',
  1901. label: 'スーパーチャット',
  1902. default: true,
  1903. }),
  1904. ],
  1905. }),
  1906. // new MidConfig.Items.CheckBox({
  1907. // id: 'japaneseOnly',
  1908. // label: '日本語のコメントのみ (Beta)',
  1909. // default: false,
  1910. // }),
  1911. ],
  1912. },
  1913. {
  1914. id: 'other',
  1915. label: 'その他',
  1916. child: [
  1917. new Items_Button({
  1918. id: 'import',
  1919. type: 'solid',
  1920. label: '設定をインポートする',
  1921. text: 'インポート',
  1922. onClick: () => {
  1923. const value = window.prompt('インポート');
  1924. if (value) {
  1925. let r###lt = false;
  1926. try {
  1927. r###lt = config.setJSON(JSON.parse(value));
  1928. }
  1929. catch (e) {
  1930. console.error(e);
  1931. }
  1932. window.alert(r###lt ? 'インポートしました' : 'インポートに失敗しました');
  1933. }
  1934. },
  1935. }),
  1936. new Items_Button({
  1937. id: 'export',
  1938. type: 'solid',
  1939. label: '設定をエクスポートする',
  1940. text: 'エクスポート',
  1941. onClick: () => {
  1942. window.prompt('エクスポート', JSON.stringify(config.getJSON()));
  1943. },
  1944. }),
  1945. new Items_Button({
  1946. id: 'reset',
  1947. type: 'outline-red',
  1948. label: '設定をリセットする',
  1949. text: 'リセット',
  1950. onClick: () => {
  1951. if (window.confirm('リセットしますか?')) {
  1952. config.reset();
  1953. configData.old = configData.now = config.getJSON();
  1954. if (typeof handlers?.onApply === 'function') {
  1955. handlers.onApply();
  1956. }
  1957. }
  1958. },
  1959. }),
  1960. ],
  1961. },
  1962. ],
  1963. buttons: [
  1964. new Items_Button({
  1965. id: 'cancel',
  1966. text: 'キャンセル',
  1967. type: 'solid',
  1968. onClick: () => {
  1969. if (typeof handlers?.onCancel === 'function') {
  1970. handlers.onCancel();
  1971. }
  1972. },
  1973. }),
  1974. new Items_ButtonEmpty(),
  1975. new Items_Button({
  1976. id: 'apply',
  1977. text: '適用',
  1978. type: 'fill-alpha',
  1979. onClick: () => {
  1980. configData.now = config.getJSON();
  1981. if (typeof handlers?.onApply === 'function') {
  1982. handlers.onApply();
  1983. }
  1984. },
  1985. }),
  1986. new Items_Button({
  1987. id: 'save',
  1988. text: '保存',
  1989. type: 'fill',
  1990. onClick: () => {
  1991. config.save();
  1992. configData.now = config.getJSON();
  1993. if (typeof handlers?.onSave === 'function') {
  1994. handlers.onSave();
  1995. }
  1996. },
  1997. }),
  1998. ],
  1999. });
  2000. return config;
  2001. };
  2002. const getFlowCommentsOption = ({ data }) => {
  2003. const option = {};
  2004. const resolution = data['general']['resolution'];
  2005. if (isConfigItemData(resolution)) {
  2006. if (resolution.value === 'auto') {
  2007. option.autoResolution = true;
  2008. option.resolution = void 0;
  2009. }
  2010. else {
  2011. option.autoResolution = false;
  2012. option.resolution = {
  2013. 'r_1080': 1080,
  2014. 'r_720': 720,
  2015. 'r_480': 480,
  2016. 'r_360': 360,
  2017. }[resolution.value];
  2018. }
  2019. }
  2020. const line = data['general']['line'];
  2021. if (isConfigItemData(line)) {
  2022. option.lines = line.value;
  2023. }
  2024. const smoothRender = data['general']['smoothRender'];
  2025. if (isConfigItemData(smoothRender)) {
  2026. option.smoothRender = smoothRender.value;
  2027. }
  2028. return option;
  2029. };
  2030. const getFlowCommentsStyle = ({ data }, name = 'default') => {
  2031. const style = {};
  2032. const configComment = data['comments'][name];
  2033. if (!isConfigItemData(configComment)) {
  2034. if (configComment['color'].checked) {
  2035. style.color = configComment['color'].value;
  2036. }
  2037. else if (name === 'default') {
  2038. style.color = configComment['color'].default;
  2039. }
  2040. if (configComment['fontScale'].checked) {
  2041. style.fontScale = configComment['fontScale'].value * 0.01;
  2042. }
  2043. else if (name === 'default') {
  2044. style.fontScale = configComment['fontScale'].default * 0.01;
  2045. }
  2046. if (configComment['fontWeight'].checked) {
  2047. style.fontWeight = configComment['fontWeight'].value;
  2048. }
  2049. else if (name === 'default') {
  2050. style.fontWeight = configComment['fontWeight'].default;
  2051. }
  2052. if (configComment['shadowColor'].checked) {
  2053. style.shadowColor = configComment['shadowColor'].value;
  2054. }
  2055. else if (name === 'default') {
  2056. style.shadowColor = configComment['shadowColor'].default;
  2057. }
  2058. if (configComment['opacity'].checked) {
  2059. style.opacity = configComment['opacity'].value * 0.01;
  2060. }
  2061. else if (name === 'default') {
  2062. style.opacity = configComment['opacity'].default * 0.01;
  2063. }
  2064. }
  2065. return style;
  2066. };
  2067. const getFilterComments = ({ data }) => {
  2068. const r###lt = {
  2069. normal: true,
  2070. member: true,
  2071. moderator: true,
  2072. owner: true,
  2073. paid: true,
  2074. };
  2075. const configFilterComments = data['filter']['comments'];
  2076. if (!isConfigItemData(configFilterComments)) {
  2077. r###lt.normal = configFilterComments['normal'].value;
  2078. r###lt.member = configFilterComments['member'].value;
  2079. r###lt.moderator = configFilterComments['moderator'].value;
  2080. r###lt.owner = configFilterComments['owner'].value;
  2081. r###lt.paid = configFilterComments['paid'].value;
  2082. }
  2083. return r###lt;
  2084. };
  2085. ;// CONCATENATED MODULE: ./src/index.ts
  2086. //----------------------------------------
  2087. // iframe(チャット欄)
  2088. //----------------------------------------
  2089. if (window !== window.parent) {
  2090. /** 除外するセレクター */
  2091. const exSelector = [
  2092. '#pinned-message',
  2093. '#docked-item',
  2094. '#live-chat-banner',
  2095. '#panel-pages',
  2096. '.yt-live-chat-docked-message',
  2097. ].join();
  2098. /****************************************
  2099. * 監視
  2100. */
  2101. const obs = new MutationObserver(mutationRecord => {
  2102. const data = mutationRecord.map(({ target }) => {
  2103. if (!(target instanceof HTMLElement) ||
  2104. target.closest(exSelector) !== null
  2105. // target.classList.contains('mid-yt-notjp')
  2106. )
  2107. return;
  2108. const type = getChatTypeFromTagName(target.tagName.toLowerCase());
  2109. if (type === null)
  2110. return;
  2111. const extData = extractChatData(target);
  2112. return {
  2113. type: type,
  2114. data: extData,
  2115. };
  2116. }).filter(Boolean);
  2117. // iframeの親Windowにコメントを送信
  2118. if (0 < data.length) {
  2119. window.parent.postMessage({
  2120. mid_chat_data: data
  2121. });
  2122. }
  2123. });
  2124. obs.observe(document.body, { childList: true, subtree: true });
  2125. }
  2126. //----------------------------------------
  2127. // 通常のページ
  2128. //----------------------------------------
  2129. else {
  2130. let fc = null;
  2131. const configData = {
  2132. old: null,
  2133. now: null,
  2134. };
  2135. const config = useConfig(configData, {
  2136. // キャンセル
  2137. onCancel: () => {
  2138. if (configData.now !== configData.old) {
  2139. configData.now = configData.old;
  2140. }
  2141. if (configData.now !== null) {
  2142. config.setJSON(configData.now);
  2143. fc?.changeOption(getFlowCommentsOption(configData.now));
  2144. fc?.changeStyle(getFlowCommentsStyle(configData.now));
  2145. }
  2146. config.remove();
  2147. },
  2148. // 適用
  2149. onApply: () => {
  2150. if (configData.now !== null) {
  2151. fc?.changeOption(getFlowCommentsOption(configData.now));
  2152. fc?.changeStyle(getFlowCommentsStyle(configData.now));
  2153. }
  2154. },
  2155. // 保存
  2156. onSave: () => {
  2157. if (configData.old !== configData.now) {
  2158. configData.old = configData.now;
  2159. }
  2160. if (configData.now !== null) {
  2161. fc?.changeOption(getFlowCommentsOption(configData.now));
  2162. fc?.changeStyle(getFlowCommentsStyle(configData.now));
  2163. }
  2164. config.remove();
  2165. }
  2166. });
  2167. configData.old = configData.now = config.getJSON();
  2168. // @ts-ignore
  2169. if (typeof GM_registerMenuCommand === 'function') {
  2170. // @ts-ignore
  2171. GM_registerMenuCommand('設定', () => {
  2172. document.body.appendChild(config);
  2173. });
  2174. }
  2175. //----------------------------------------
  2176. // iframe(チャット)からコメントを受け取ったとき
  2177. //----------------------------------------
  2178. window.addEventListener('message', ({ data }) => {
  2179. if (data.mid_chat_data !== void 0) {
  2180. const mid_chat_data = data.mid_chat_data;
  2181. //----------------------------------------
  2182. // コメントエリアを追加
  2183. //----------------------------------------
  2184. if (fc === null) {
  2185. const ytdPlayer = document.getElementById('ytd-player');
  2186. const flowComments = ytdPlayer?.getElementsByClassName(CONFIG.CANVAS_CLASSNAME)[0];
  2187. const videoContainer = ytdPlayer?.getElementsByClassName('html5-video-container')[0];
  2188. if (flowComments === void 0 &&
  2189. videoContainer instanceof HTMLElement) {
  2190. fc = new Main();
  2191. if (configData.now !== null) {
  2192. fc.changeOption(getFlowCommentsOption(configData.now));
  2193. fc.changeStyle(getFlowCommentsStyle(configData.now));
  2194. }
  2195. videoContainer.insertAdjacentElement('afterend', fc.canvas);
  2196. }
  2197. }
  2198. //----------------------------------------
  2199. // コメントを流す
  2200. //----------------------------------------
  2201. if (fc?.isStarted &&
  2202. mid_chat_data.length < 10) {
  2203. const filterComments = getFilterComments(configData.now);
  2204. const flowCommentsStyles = {
  2205. member: getFlowCommentsStyle(configData.now, 'member'),
  2206. moderator: getFlowCommentsStyle(configData.now, 'moderator'),
  2207. owner: getFlowCommentsStyle(configData.now, 'owner'),
  2208. };
  2209. mid_chat_data.forEach(({ type, data }) => {
  2210. if (
  2211. // 通常
  2212. ((type === CHAT_TYPE.TEXT && data.author.type === AUTHOR_TYPE.USER) &&
  2213. !filterComments.normal) ||
  2214. // スーパーチャット
  2215. ((type === CHAT_TYPE.PAID || type === CHAT_TYPE.PAID_STICKER) &&
  2216. !filterComments.paid) ||
  2217. // メンバー
  2218. (data.author.type === AUTHOR_TYPE.MEMBER &&
  2219. !filterComments.member) ||
  2220. // モデレーター
  2221. (data.author.type === AUTHOR_TYPE.MODERATOR &&
  2222. !filterComments.moderator) ||
  2223. // チャンネル
  2224. (data.author.type === AUTHOR_TYPE.OWNER &&
  2225. !filterComments.owner))
  2226. return;
  2227. const content = [];
  2228. let style = {};
  2229. //----------------------------------------
  2230. // コメントのスタイルを指定
  2231. //----------------------------------------
  2232. // スーパーチャット
  2233. if (type === CHAT_TYPE.PAID ||
  2234. type === CHAT_TYPE.PAID_STICKER) {
  2235. style.color = data.paid.color || void 0;
  2236. }
  2237. // メンバーシップ
  2238. else if (type === CHAT_TYPE.MEMBERSHIP) {
  2239. style = flowCommentsStyles.member;
  2240. if (style.color === void 0) {
  2241. style.color = COLOR.MEMBER;
  2242. }
  2243. }
  2244. // メンバー
  2245. else if (data.author.type === AUTHOR_TYPE.MEMBER) {
  2246. style = flowCommentsStyles.member;
  2247. if (style.color === void 0) {
  2248. style.color = COLOR.MEMBER;
  2249. }
  2250. }
  2251. // モデレーター
  2252. else if (data.author.type === AUTHOR_TYPE.MODERATOR) {
  2253. style = flowCommentsStyles.moderator;
  2254. if (style.color === void 0) {
  2255. style.color = COLOR.MODERATOR;
  2256. }
  2257. }
  2258. // オーナー
  2259. else if (data.author.type === AUTHOR_TYPE.OWNER) {
  2260. style = flowCommentsStyles.owner;
  2261. if (style.color === void 0) {
  2262. style.color = COLOR.OWNER;
  2263. }
  2264. }
  2265. //----------------------------------------
  2266. // コメントの先頭につけるやつ
  2267. //----------------------------------------
  2268. // スーパーチャット
  2269. if ((type === CHAT_TYPE.PAID ||
  2270. type === CHAT_TYPE.PAID_STICKER) && (data.author.name !== null &&
  2271. data.paid.purchase !== null)) {
  2272. content.push(`${data.author.name} [${data.paid.purchase}]`);
  2273. }
  2274. // モデレーター
  2275. else if (data.author.type === AUTHOR_TYPE.MODERATOR &&
  2276. data.author.name !== null) {
  2277. content.push(data.author.name || '');
  2278. }
  2279. //----------------------------------------
  2280. // コメント本文を追加
  2281. //----------------------------------------
  2282. if (0 < data.items.length &&
  2283. (type === CHAT_TYPE.TEXT ||
  2284. type === CHAT_TYPE.MEMBERSHIP)) {
  2285. if (0 < content.length) {
  2286. content.push(': ');
  2287. }
  2288. // 本文
  2289. data.items.forEach(item => {
  2290. if (item.type === 'text' &&
  2291. item.text !== null) {
  2292. content.push(item.text);
  2293. }
  2294. else if (item.type === 'image' &&
  2295. item.src !== null) {
  2296. content.push(new image_Image(item.src));
  2297. }
  2298. });
  2299. }
  2300. //----------------------------------------
  2301. // コメントを流す
  2302. //----------------------------------------
  2303. fc?.pushComment(new Item(data.id || Symbol(), content, void 0, style));
  2304. });
  2305. }
  2306. else {
  2307. fc?.start();
  2308. }
  2309. }
  2310. });
  2311. //----------------------------------------
  2312. // YouTube内でページが切り替わった時のなんか
  2313. //----------------------------------------
  2314. window.addEventListener('yt-page-data-updated', () => {
  2315. fc?.dispose();
  2316. fc = null;
  2317. });
  2318. //----------------------------------------
  2319. // コンテキストメニューに設定ボタンを追加
  2320. //----------------------------------------
  2321. const obs_menu = new MutationObserver(mutationRecord => {
  2322. for (const { addedNodes } of mutationRecord) {
  2323. for (const added of addedNodes) {
  2324. if (!(added instanceof HTMLElement) ||
  2325. !added.classList.contains('ytp-popup') ||
  2326. !added.classList.contains('ytp-contextmenu') ||
  2327. added.getElementsByClassName('ytp-menuitem-midconfig').length !== 0)
  2328. continue;
  2329. const panelMenu = added.getElementsByClassName('ytp-panel-menu')[0];
  2330. const menuItem = panelMenu?.lastElementChild?.cloneNode(true);
  2331. if (menuItem instanceof HTMLElement) {
  2332. menuItem.classList.add('ytp-menuitem-midconfig');
  2333. const icon = menuItem.getElementsByClassName('ytp-menuitem-icon')[0];
  2334. if (icon instanceof HTMLElement) {
  2335. icon.innerHTML = SVG_SETTING;
  2336. }
  2337. const label = menuItem.getElementsByClassName('ytp-menuitem-label')[0];
  2338. if (label instanceof HTMLElement) {
  2339. label.textContent = 'YouTubeライブ コメント流し 設定';
  2340. }
  2341. const content = menuItem.getElementsByClassName('ytp-menuitem-content')[0];
  2342. if (content instanceof HTMLElement) {
  2343. content.innerHTML = '';
  2344. }
  2345. menuItem.addEventListener('click', () => {
  2346. document.body.appendChild(config);
  2347. config.click();
  2348. });
  2349. panelMenu.appendChild(menuItem);
  2350. if (added.firstElementChild instanceof HTMLElement) {
  2351. added.style.height = `${added.firstElementChild.scrollHeight}px`;
  2352. added.firstElementChild.style.height = `${added.firstElementChild.scrollHeight}px`;
  2353. }
  2354. }
  2355. }
  2356. }
  2357. });
  2358. obs_menu.observe(document.body, { childList: true, subtree: true });
  2359. //----------------------------------------
  2360. // CSS
  2361. //----------------------------------------
  2362. const style = `
  2363. .${CONFIG.CANVAS_CLASSNAME} {
  2364. position: relative;
  2365. width: 100%;
  2366. height: 100%;
  2367. z-index: 11;
  2368. pointer-events: none;
  2369. }
  2370. .midconfig-panel {
  2371. position: fixed;
  2372. bottom: 18px;
  2373. right: 18px;
  2374. width: ${500}px;
  2375. height: ${500 * (3 / 4)}px;
  2376. z-index: 9999;
  2377. }
  2378. `;
  2379. document.head.insertAdjacentHTML('beforeend', `<style id="${CONFIG.CANVAS_CLASSNAME}-style">${style}</style>`);
  2380. }
  2381. /******/ })()
  2382. ;