Torn.com Enhanced Chat Buttons V2

Add customizable buttons to Torn.com chat with enhanced UI and features

当前为 2024-05-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Torn.com Enhanced Chat Buttons V2
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.10
  5. // @description Add customizable buttons to Torn.com chat with enhanced UI and features
  6. // @author Created by Callz [2188704], updated by Weav3r [1853324]
  7. // @match https://www.torn.com/*
  8. // @grant GM_setClipboard
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. const buttonCSS = `
  15. .custom-chat-button {
  16. background-color: #007BFF;
  17. color: white;
  18. padding: 2px 7px;
  19. text-align: center;
  20. text-decoration: none;
  21. display: inline-block;
  22. font-size: 14px;
  23. margin: 4px 6px;
  24. cursor: pointer;
  25. border-radius: 5px;
  26. border: none;
  27. transition: transform 0.1s ease, box-shadow 0.1s ease;
  28. min-width: 80px;
  29. overflow: hidden;
  30. white-space: nowrap;
  31. }
  32.  
  33. .custom-chat-button:active {
  34. transform: scale(0.95);
  35. box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  36. }
  37.  
  38. .custom-chat-button.recent {
  39. border: 2px solid #FFD700;
  40. box-shadow: 0 0 5px rgba(255, 215, 0, 0.8);
  41. }
  42.  
  43. .custom-ui-panel {
  44. position: fixed;
  45. top: 50%;
  46. left: 50%;
  47. transform: translate(-50%, -50%);
  48. background-color: #f5f5f5;
  49. padding: 10px;
  50. color: black;
  51. border-radius: 10px;
  52. box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  53. z-index: 9999999999;
  54. width: 90%;
  55. max-width: 500px;
  56. box-sizing: border-box;
  57. max-height: 90vh;
  58. overflow: auto;
  59. }
  60.  
  61. .custom-ui-panel h3 {
  62. font-size: 20px;
  63. margin-bottom: 10px;
  64. text-align: center;
  65. }
  66.  
  67. .custom-ui-panel label {
  68. font-size: 14px;
  69. margin-bottom: 5px;
  70. display: block;
  71. }
  72.  
  73. .custom-ui-panel input[type="text"],
  74. .custom-ui-panel select,
  75. .custom-ui-panel textarea {
  76. width: calc(100% - 12px);
  77. padding: 5px;
  78. margin-bottom: 10px;
  79. border: 1px solid #ccc;
  80. border-radius: 5px;
  81. font-size: 14px;
  82. }
  83.  
  84. .custom-ui-panel input[type="color"] {
  85. padding: 0;
  86. margin-top: 5px;
  87. }
  88.  
  89. .custom-ui-panel button {
  90. background-color: #007BFF;
  91. color: white;
  92. border: none;
  93. padding: 8px 12px;
  94. border-radius: 5px;
  95. cursor: pointer;
  96. margin: 5px;
  97. font-size: 14px;
  98. transition: background-color 0.3s ease;
  99. }
  100.  
  101. .custom-ui-panel button#close-ui {
  102. background-color: #ccc;
  103. }
  104.  
  105. .custom-ui-panel button#close-ui:hover {
  106. background-color: #999;
  107. }
  108.  
  109. .custom-ui-panel textarea {
  110. height: 60px;
  111. resize: vertical;
  112. position: relative;
  113. }
  114.  
  115. .custom-ui-panel hr {
  116. margin: 10px 0;
  117. border: 0;
  118. border-top: 1px solid #ccc;
  119. }
  120.  
  121. .char-counter {
  122. position: absolute;
  123. bottom: 10px;
  124. right: 10px;
  125. font-size: 12px;
  126. color: #999;
  127. }
  128.  
  129. #chat-config-button {
  130. color: green;
  131. }
  132.  
  133. #button-configs {
  134. max-height: 400px;
  135. overflow-y: auto;
  136. margin-bottom: 10px;
  137. }
  138.  
  139. @media (max-width: 600px) {
  140. .custom-ui-panel {
  141. width: 95%;
  142. max-width: none;
  143. padding: 8px;
  144. }
  145.  
  146. .custom-ui-panel h3 {
  147. font-size: 18px;
  148. }
  149.  
  150. .custom-ui-panel label,
  151. .custom-ui-panel button {
  152. font-size: 12px;
  153. }
  154.  
  155. .custom-ui-panel input[type="text"],
  156. .custom-ui-panel select,
  157. .custom-ui-panel textarea {
  158. font-size: 12px;
  159. }
  160.  
  161. .custom-ui-panel button {
  162. padding: 6px 10px;
  163. }
  164.  
  165. .char-counter {
  166. font-size: 10px;
  167. }
  168. }
  169.  
  170. .tabs {
  171. display: flex;
  172. margin-bottom: 10px;
  173. }
  174.  
  175. .tab {
  176. flex: 1;
  177. padding: 10px;
  178. cursor: pointer;
  179. text-align: center;
  180. background-color: #e9e9e9;
  181. border: 1px solid #ccc;
  182. border-bottom: none;
  183. border-radius: 10px 10px 0 0;
  184. }
  185.  
  186. .tab.settings-tab {
  187. flex: 0.2;
  188. padding: 10px;
  189. cursor: pointer;
  190. text-align: center;
  191. background-color: #e9e9e9;
  192. border: 1px solid #ccc;
  193. border-bottom: none;
  194. border-radius: 10px 10px 0 0;
  195. }
  196.  
  197. .tab.active {
  198. background-color: #fff;
  199. border-bottom: 1px solid #fff;
  200. }
  201.  
  202. .tab-content {
  203. display: none;
  204. }
  205.  
  206. .tab-content.active {
  207. display: block;
  208. }
  209.  
  210. .custom-ui-panel.config-list-tab-active {
  211. max-height: 80vh;
  212. }
  213.  
  214. .search-container {
  215. display: flex;
  216. margin-bottom: 10px;
  217. }
  218.  
  219. .search-container input[type="text"] {
  220. flex: 3;
  221. padding: 5px;
  222. margin-right: 5px;
  223. }
  224.  
  225. .search-container select {
  226. flex: 1;
  227. padding: 5px;
  228. }
  229.  
  230. .highlight {
  231. background-color: yellow;
  232. }
  233.  
  234. .tt-chat-filter {
  235. display: flex;
  236. padding: 4px;
  237. align-items: center;
  238. background-color: var(--chat-box-bg);
  239. color: var(--chat-box-label-info);
  240. border-bottom: 1px solid var(--chat-box-input-border);
  241. margin-bottom: 8px;
  242. }
  243.  
  244. .tt-chat-filter input {
  245. margin-left: 4px;
  246. margin-right: 4px;
  247. border-radius: 5px;
  248. width: -webkit-fill-available;
  249. width: -moz-available;
  250. border: 1px solid var(--chat-box-input-border);
  251. background-color: var(--chat-box-bg);
  252. color: var(--chat-box-label-info);
  253. }
  254. `;
  255.  
  256. const conditions = {
  257. TradeChat: chatBox => chatBox.querySelector('.chat-box-header__name___jIjjM').textContent === 'Trade',
  258. HospitalChat: chatBox => chatBox.querySelector('.chat-box-header__name___jIjjM').textContent === 'Hospital',
  259. FactionChat: chatBox => chatBox.querySelector('.chat-box-header__name___jIjjM').textContent === 'Faction',
  260. CompanyChat: chatBox => chatBox.querySelector('.chat-box-header__name___jIjjM').textContent === 'Company',
  261. GlobalChat: chatBox => chatBox.querySelector('.chat-box-header__name___jIjjM').textContent === 'Global',
  262. UserChat: chatBox => chatBox.querySelector('.chat-box-header__options___nTsMU'),
  263. };
  264.  
  265. const companyTypes = {
  266. 1: "Adult Novelties",
  267. 2: "Amusement Park",
  268. 3: "Candle Shop",
  269. 4: "Car Dealership",
  270. 5: "Clothing Store",
  271. 6: "Cruise Line",
  272. 7: "Cyber Cafe",
  273. 8: "Detective Agency",
  274. 9: "Farm",
  275. 10: "Firework Stand",
  276. 11: "Fitness Center",
  277. 12: "Flower Shop",
  278. 13: "Furniture Store",
  279. 14: "Game Shop",
  280. 15: "Gas Station",
  281. 16: "Gents Strip Club",
  282. 17: "Grocery Store",
  283. 18: "Gun Shop",
  284. 19: "Hair Salon",
  285. 20: "Ladies Strip Club",
  286. 21: "Law Firm",
  287. 22: "Lingerie Store",
  288. 23: "Logistics Management",
  289. 24: "Meat Warehouse",
  290. 25: "Mechanic Shop",
  291. 26: "Mining Corporation",
  292. 27: "Music Store",
  293. 28: "Nightclub",
  294. 29: "Oil Rig",
  295. 30: "Private Security Firm",
  296. 31: "Property Broker",
  297. 32: "Pub",
  298. 33: "Restaurant",
  299. 34: "Software Corporation",
  300. 35: "Sweet Shop",
  301. 36: "Television Network",
  302. 37: "Theater",
  303. 38: "Toy Shop",
  304. 39: "Zoo"
  305. };
  306.  
  307. function addCSS(cssString) {
  308. const style = document.createElement('style');
  309. style.textContent = cssString;
  310. document.head.append(style);
  311. }
  312.  
  313. function saveRecentButtonInfo(buttonText, chatBoxName) {
  314. localStorage.setItem('recentButtonInfo', JSON.stringify({ buttonText, chatBoxName }));
  315. }
  316.  
  317. function clearRecentButtonInfo() {
  318. localStorage.removeItem('recentButtonInfo');
  319. }
  320.  
  321. function getButtonConfigurations() {
  322. return JSON.parse(localStorage.getItem('chatButtonConfig')) || { buttons: [] };
  323. }
  324.  
  325. function saveButtonConfigurations(config) {
  326. localStorage.setItem('chatButtonConfig', JSON.stringify(config));
  327. }
  328.  
  329. function getAPIKey() {
  330. return localStorage.getItem('apiKey') || '';
  331. }
  332.  
  333. function saveAPIKey(key) {
  334. localStorage.setItem('apiKey', key);
  335. }
  336.  
  337. function createUIPanel() {
  338. const panel = document.createElement('div');
  339. panel.className = 'custom-ui-panel';
  340. panel.innerHTML = `
  341. <div class="tabs">
  342. <div class="tab active" data-tab="config-list-tab">Configured Buttons</div>
  343. <div class="tab" data-tab="config-edit-tab">Create/Edit Button</div>
  344. <div class="tab settings-tab" data-tab="config-settings-tab">⚙️</div>
  345. </div>
  346. <div id="config-list-tab" class="tab-content active">
  347. <div class="search-container">
  348. <input type="text" id="search-input" placeholder="Search...">
  349. <select id="search-select">
  350. <option value="buttonText">Text</option>
  351. <option value="condition">Condition</option>
  352. <option value="text">Message</option>
  353. </select>
  354. </div>
  355. <div id="button-configs"></div>
  356. </div>
  357. <div id="config-edit-tab" class="tab-content">
  358. <div>
  359. <label for="button-text">Button Text</label>
  360. <input type="text" id="button-text" placeholder="Button Text">
  361.  
  362. <label for="button-color">Background Color</label>
  363. <input type="color" id="button-color">
  364.  
  365. <label for="button-condition">Condition</label>
  366. <select id="button-condition">
  367. <option value="TradeChat">Trade Chat</option>
  368. <option value="HospitalChat">Hospital Chat</option>
  369. <option value="FactionChat">Faction Chat</option>
  370. <option value="CompanyChat">Company Chat</option>
  371. <option value="GlobalChat">Global Chat</option>
  372. <option value="UserChat">User Chat</option>
  373. </select>
  374.  
  375. <label for="button-text-content">Message</label>
  376. <textarea id="button-text-content" placeholder="Message content"></textarea>
  377. <div class="char-counter" id="char-counter">0</div>
  378.  
  379. <button id="add-button">Add Button</button>
  380. <button id="edit-button" style="display: none;">Save Button</button>
  381. </div>
  382. </div>
  383. <div id="config-settings-tab" class="tab-content">
  384. <label for="api-key">API Key</label>
  385. <input type="text" id="api-key" placeholder="Enter your API key" value="${getAPIKey()}">
  386. <button id="import-button">Import Config</button>
  387. <button id="export-button">Export Config</button>
  388. </div>
  389. <button id="close-ui">Close</button>
  390. `;
  391. document.body.appendChild(panel);
  392.  
  393. document.querySelectorAll('.tab').forEach(tab => {
  394. tab.addEventListener('click', () => {
  395. switchTab(tab.dataset.tab);
  396. });
  397. });
  398.  
  399. document.getElementById('add-button').addEventListener('click', addNewButtonConfig);
  400. document.getElementById('edit-button').addEventListener('click', editButtonConfig);
  401. document.getElementById('close-ui').addEventListener('click', closeUI);
  402. document.getElementById('import-button').addEventListener('click', importConfig);
  403. document.getElementById('export-button').addEventListener('click', exportConfig);
  404. document.getElementById('button-text-content').addEventListener('input', updateCharCounter);
  405. document.getElementById('search-input').addEventListener('input', filterButtonConfigs);
  406. document.getElementById('api-key').addEventListener('input', (e) => saveAPIKey(e.target.value));
  407. populateButtonConfigs();
  408. }
  409.  
  410. function switchTab(tabId) {
  411. document.querySelectorAll('.tab, .tab-content').forEach(el => {
  412. el.classList.remove('active');
  413. });
  414. document.querySelector(`[data-tab="${tabId}"]`).classList.add('active');
  415. document.getElementById(tabId).classList.add('active');
  416.  
  417. const panel = document.querySelector('.custom-ui-panel');
  418. if (tabId === 'config-list-tab') {
  419. panel.classList.add('config-list-tab-active');
  420. } else {
  421. panel.classList.remove('config-list-tab-active');
  422. }
  423. }
  424.  
  425. function populateButtonConfigs() {
  426. const configsContainer = document.getElementById('button-configs');
  427. configsContainer.innerHTML = '';
  428. const configs = getButtonConfigurations();
  429.  
  430. configs.buttons.forEach((buttonConfig, index) => {
  431. const configDiv = document.createElement('div');
  432. configDiv.className = 'draggable';
  433. configDiv.dataset.index = index;
  434. configDiv.innerHTML = `
  435. <div><strong>Text:</strong> ${buttonConfig.buttonText}</div>
  436. <div><strong>Color:</strong> ${buttonConfig.backgroundColor}</div>
  437. <div><strong>Condition:</strong> ${buttonConfig.condition}</div>
  438. <div><strong>Message:</strong> ${buttonConfig.text}</div>
  439. `;
  440.  
  441. const editButton = document.createElement('button');
  442. editButton.textContent = 'Edit';
  443. editButton.addEventListener('click', () => {
  444. selectForEdit(index);
  445. switchTab('config-edit-tab');
  446. });
  447. configDiv.appendChild(editButton);
  448.  
  449. const deleteButton = document.createElement('button');
  450. deleteButton.textContent = 'Delete';
  451. deleteButton.addEventListener('click', () => deleteButtonConfig(index));
  452. configDiv.appendChild(deleteButton);
  453.  
  454. const moveUpButton = document.createElement('button');
  455. moveUpButton.textContent = 'Up';
  456. moveUpButton.addEventListener('click', () => moveButtonConfig(index, -1));
  457. configDiv.appendChild(moveUpButton);
  458.  
  459. const moveDownButton = document.createElement('button');
  460. moveDownButton.textContent = 'Down';
  461. moveDownButton.addEventListener('click', () => moveButtonConfig(index, 1));
  462. configDiv.appendChild(moveDownButton);
  463.  
  464. configsContainer.appendChild(configDiv);
  465. });
  466. }
  467.  
  468. function filterButtonConfigs() {
  469. const searchInput = document.getElementById('search-input').value.toLowerCase();
  470. const searchBy = document.getElementById('search-select').value;
  471. const configs = getButtonConfigurations();
  472.  
  473. const filteredConfigs = configs.buttons.filter(buttonConfig => {
  474. const fieldValue = buttonConfig[searchBy].toLowerCase();
  475. return fieldValue.includes(searchInput);
  476. });
  477.  
  478. const configsContainer = document.getElementById('button-configs');
  479. configsContainer.innerHTML = '';
  480.  
  481. filteredConfigs.forEach((buttonConfig, index) => {
  482. const configDiv = document.createElement('div');
  483. configDiv.className = 'draggable';
  484. configDiv.dataset.index = index;
  485. configDiv.innerHTML = `
  486. <div><strong>Text:</strong> ${buttonConfig.buttonText}</div>
  487. <div><strong>Color:</strong> ${buttonConfig.backgroundColor}</div>
  488. <div><strong>Condition:</strong> ${buttonConfig.condition}</div>
  489. <div><strong>Message:</strong> ${buttonConfig.text}</div>
  490. `;
  491.  
  492. const editButton = document.createElement('button');
  493. editButton.textContent = 'Edit';
  494. editButton.addEventListener('click', () => {
  495. selectForEdit(index);
  496. switchTab('config-edit-tab');
  497. });
  498. configDiv.appendChild(editButton);
  499.  
  500. const deleteButton = document.createElement('button');
  501. deleteButton.textContent = 'Delete';
  502. deleteButton.addEventListener('click', () => deleteButtonConfig(index));
  503. configDiv.appendChild(deleteButton);
  504.  
  505. const moveUpButton = document.createElement('button');
  506. moveUpButton.textContent = 'Up';
  507. moveUpButton.addEventListener('click', () => moveButtonConfig(index, -1));
  508. configDiv.appendChild(moveUpButton);
  509.  
  510. const moveDownButton = document.createElement('button');
  511. moveDownButton.textContent = 'Down';
  512. moveDownButton.addEventListener('click', () => moveButtonConfig(index, 1));
  513. configDiv.appendChild(moveDownButton);
  514.  
  515. configsContainer.appendChild(configDiv);
  516. });
  517. }
  518.  
  519. function selectForEdit(index) {
  520. const config = getButtonConfigurations().buttons[index];
  521. document.getElementById('button-text').value = config.buttonText;
  522. document.getElementById('button-color').value = config.backgroundColor;
  523. document.getElementById('button-condition').value = config.condition;
  524. document.getElementById('button-text-content').value = config.text;
  525.  
  526. document.getElementById('add-button').style.display = 'block';
  527. document.getElementById('edit-button').style.display = 'block';
  528. document.getElementById('edit-button').setAttribute('data-edit-index', index);
  529. }
  530.  
  531. function deleteButtonConfig(index) {
  532. const config = getButtonConfigurations();
  533. config.buttons.splice(index, 1);
  534. saveButtonConfigurations(config);
  535. populateButtonConfigs();
  536. }
  537.  
  538. function moveButtonConfig(index, direction) {
  539. const config = getButtonConfigurations();
  540. const newIndex = index + direction;
  541.  
  542. if (newIndex >= 0 && newIndex < config.buttons.length) {
  543. const buttonConfig = config.buttons.splice(index, 1)[0];
  544. config.buttons.splice(newIndex, 0, buttonConfig);
  545. saveButtonConfigurations(config);
  546. populateButtonConfigs();
  547. }
  548. }
  549.  
  550. function addNewButtonConfig() {
  551. const buttonText = document.getElementById('button-text').value;
  552. const backgroundColor = document.getElementById('button-color').value;
  553. const condition = document.getElementById('button-condition').value;
  554. const text = document.getElementById('button-text-content').value;
  555.  
  556. const config = getButtonConfigurations();
  557. config.buttons.push({ buttonText, backgroundColor, condition, text });
  558. saveButtonConfigurations(config);
  559. populateButtonConfigs();
  560. highlightButton(config.buttons.length - 1);
  561. switchTab('config-list-tab');
  562.  
  563. clearInputFields();
  564. }
  565.  
  566. function editButtonConfig() {
  567. const index = parseInt(document.getElementById('edit-button').getAttribute('data-edit-index'), 10);
  568. const buttonText = document.getElementById('button-text').value;
  569. const backgroundColor = document.getElementById('button-color').value;
  570. const condition = document.getElementById('button-condition').value;
  571. const text = document.getElementById('button-text-content').value;
  572.  
  573. const config = getButtonConfigurations();
  574. config.buttons[index] = { buttonText, backgroundColor, condition, text };
  575. saveButtonConfigurations(config);
  576. populateButtonConfigs();
  577. highlightButton(index);
  578. switchTab('config-list-tab');
  579.  
  580. document.getElementById('add-button').style.display = 'block';
  581. document.getElementById('edit-button').style.display = 'none';
  582.  
  583. clearInputFields();
  584. }
  585.  
  586. function clearInputFields() {
  587. document.getElementById('button-text').value = '';
  588. document.getElementById('button-text-content').value = '';
  589. }
  590.  
  591. function closeUI() {
  592. document.querySelector('.custom-ui-panel').remove();
  593. }
  594.  
  595. function createConfigButton() {
  596. const settingsPanel = document.querySelector('.settings-panel___IZSDs');
  597. if (settingsPanel && !document.querySelector('#chat-config-button')) {
  598. const configButton = document.createElement('button');
  599. configButton.id = 'chat-config-button';
  600. configButton.textContent = 'Edit Chat Buttons';
  601. configButton.addEventListener('click', createUIPanel);
  602. settingsPanel.appendChild(configButton);
  603. }
  604. }
  605.  
  606. async function applyButtonConfigurations() {
  607. const configs = getButtonConfigurations();
  608. document.querySelectorAll('.chat-box___mHm01').forEach(chatBox => {
  609. configs.buttons.forEach(buttonConfig => {
  610. const conditionFunc = conditions[buttonConfig.condition];
  611. if (conditionFunc && conditionFunc(chatBox) && !chatBox.querySelector(`[data-button-text="${buttonConfig.buttonText}"]`)) {
  612. const button = document.createElement('button');
  613. button.className = 'custom-chat-button';
  614. button.innerText = buttonConfig.buttonText;
  615. button.style.backgroundColor = buttonConfig.backgroundColor;
  616. button.setAttribute('data-button-text', buttonConfig.buttonText);
  617. button.addEventListener('click', (event) => addCustomText(chatBox, buttonConfig.text, event));
  618. button.addEventListener('mousedown', (event) => {
  619. if (event.button === 0) { // Left mouse button
  620. let timer;
  621. const delay = 1000; // 1 second
  622.  
  623. timer = setTimeout(() => {
  624. button.classList.remove('recent');
  625. clearRecentButtonInfo();
  626. }, delay);
  627.  
  628. button.addEventListener('mouseup', () => {
  629. clearTimeout(timer);
  630. }, { once: true });
  631.  
  632. button.addEventListener('mouseleave', () => {
  633. clearTimeout(timer);
  634. }, { once: true });
  635. }
  636. });
  637.  
  638. // Add button to the appropriate container
  639. const filterContainer = chatBox.querySelector('.tt-chat-filter');
  640. const footerContainer = chatBox.querySelector('.chat-box-footer___YK914');
  641. if (filterContainer) {
  642. filterContainer.insertBefore(button, filterContainer.firstChild);
  643. } else if (footerContainer) {
  644. const buttonContainer = chatBox.querySelector('.button-container') || document.createElement('div');
  645. buttonContainer.className = 'button-container';
  646. buttonContainer.style.display = 'flex';
  647. buttonContainer.style.flexWrap = 'wrap';
  648. footerContainer.insertAdjacentElement('beforebegin', buttonContainer);
  649. buttonContainer.appendChild(button);
  650. } else {
  651. const buttonContainer = document.createElement('div');
  652. buttonContainer.className = 'button-container';
  653. buttonContainer.style.display = 'flex';
  654. buttonContainer.style.flexWrap = 'wrap';
  655. chatBox.insertBefore(buttonContainer, chatBox.firstChild);
  656. buttonContainer.appendChild(button);
  657. }
  658. }
  659. });
  660. });
  661. }
  662.  
  663. async function addCustomText(chatBox, messageTemplate, event) {
  664. const nameElement = chatBox.querySelector('.typography___Dc5WV');
  665. const name = nameElement ? nameElement.textContent.trim() : 'Trader';
  666. let message = messageTemplate.replace('{name}', name);
  667.  
  668. if (message.includes('{company}')) {
  669. message = message.replace('{company}', 'Awaiting API response...');
  670. navigator.clipboard.writeText(message);
  671.  
  672. const apiKey = getAPIKey();
  673. if (apiKey) {
  674. try {
  675. const response = await fetch(`https://api.torn.com/company/?selections=profile&key=${apiKey}`);
  676. const data = await response.json();
  677. const company = data.company;
  678. const companyType = companyTypes[company.company_type];
  679. const companyInfo = `${company.rating}* ${companyType}`;
  680. message = messageTemplate.replace('{company}', companyInfo);
  681. } catch (error) {
  682. console.error('Failed to fetch company info:', error);
  683. message = messageTemplate.replace('{company}', 'Error fetching company info');
  684. }
  685. } else {
  686. message = messageTemplate.replace('{company}', 'API key not set');
  687. }
  688. }
  689.  
  690. navigator.clipboard.writeText(message).then(() => {
  691. const textArea = chatBox.querySelector('textarea');
  692. textArea.focus();
  693. textArea.value = ''; // Clear the existing text
  694. const startPos = textArea.selectionStart;
  695. const endPos = textArea.selectionEnd;
  696. textArea.setRangeText(message, startPos, endPos, 'end');
  697. textArea.dispatchEvent(new Event('input', { bubbles: true }));
  698. textArea.focus();
  699. textArea.selectionStart = textArea.selectionEnd = startPos + message.length;
  700.  
  701. // Remove the 'recent' class from all buttons
  702. chatBox.querySelectorAll('.custom-chat-button').forEach(btn => {
  703. btn.classList.remove('recent');
  704. });
  705.  
  706. // Add the 'recent' class to the clicked button
  707. event.target.classList.add('recent');
  708.  
  709. // Save the recently clicked button information
  710. const chatBoxName = chatBox.querySelector('.chat-box-header__name___jIjjM').textContent;
  711. saveRecentButtonInfo(event.target.getAttribute('data-button-text'), chatBoxName);
  712. });
  713. }
  714.  
  715. function applyRecentButtonClass() {
  716. const recentButtonInfo = JSON.parse(localStorage.getItem('recentButtonInfo'));
  717. if (recentButtonInfo) {
  718. document.querySelectorAll('.chat-box___mHm01').forEach(chatBox => {
  719. const chatBoxName = chatBox.querySelector('.chat-box-header__name___jIjjM').textContent;
  720. if (chatBoxName === recentButtonInfo.chatBoxName) {
  721. const button = chatBox.querySelector(`[data-button-text="${recentButtonInfo.buttonText}"]`);
  722. if (button) {
  723. button.classList.add('recent');
  724. }
  725. }
  726. });
  727. }
  728. }
  729.  
  730. function importConfig() {
  731. const input = document.createElement('input');
  732. input.type = 'file';
  733. input.accept = '.json';
  734. input.onchange = (event) => {
  735. const file = event.target.files[0];
  736. const reader = new FileReader();
  737. reader.onload = (e) => {
  738. const config = JSON.parse(e.target.result);
  739. saveButtonConfigurations(config);
  740. populateButtonConfigs();
  741. applyButtonConfigurations();
  742. };
  743. reader.readAsText(file);
  744. };
  745. input.click();
  746. }
  747.  
  748. function exportConfig() {
  749. const config = getButtonConfigurations();
  750. const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' });
  751. const url = URL.createObjectURL(blob);
  752. const a = document.createElement('a');
  753. a.href = url;
  754. a.download = 'chatButtonConfig.json';
  755. document.body.appendChild(a);
  756. a.click();
  757. document.body.removeChild(a);
  758. URL.revokeObjectURL(url);
  759. }
  760.  
  761. function updateCharCounter() {
  762. const textArea = document.getElementById('button-text-content');
  763. const counter = document.getElementById('char-counter');
  764. counter.textContent = textArea.value.length;
  765. }
  766.  
  767. function highlightButton(index) {
  768. const configsContainer = document.getElementById('button-configs');
  769. const buttonDiv = configsContainer.querySelector(`.draggable[data-index="${index}"]`);
  770. if (buttonDiv) {
  771. buttonDiv.classList.add('highlight');
  772. buttonDiv.scrollIntoView({ behavior: 'smooth', block: 'center' });
  773. setTimeout(() => {
  774. buttonDiv.classList.remove('highlight');
  775. }, 2000);
  776. }
  777. }
  778.  
  779. addCSS(buttonCSS);
  780.  
  781. const chatContainerObserver = new MutationObserver(function(mutations) {
  782. mutations.forEach(function(mutation) {
  783. createConfigButton();
  784. applyButtonConfigurations();
  785. applyRecentButtonClass();
  786. });
  787. });
  788.  
  789. const chatContainer = document.querySelector('#chatRoot');
  790. if (chatContainer) {
  791. chatContainerObserver.observe(chatContainer, { childList: true, subtree: true });
  792. }
  793.  
  794. applyButtonConfigurations();
  795. applyRecentButtonClass();
  796. })();