Custom Background Manager

Web siteleri için arka plan değiştirme [öncelikli manga-manhwa siteleri]

  1. // ==UserScript==
  2. // @namespace http://Vebascans.net/
  3. // @version 2.3.2
  4. // @name Custom Background Manager
  5. // @name:es Administrador de Fondos
  6. // @name:zh 自定义背景管理器
  7. // @name:hi कस्टम बैकग्राउंड प्रबंधक
  8. // @name:ar مدير الخلفية المخصص
  9. // @name:pt Gerenciador de Plano de Fundo Personalizado
  10. // @name:ru Менеджер пользовательского фона
  11. // @name:ja カスタム背景マネージャー
  12. // @name:de Benutzerdefinierter Hintergrund-Manager
  13. // @name:fr Gestionnaire de Fond d'Écran Personnalisé
  14. // @name:it Gestore di Sfondo Personalizzato
  15. // @name:ko 사용자 지정 배경 관리자
  16. // @name:tr Özel Arka Plan Yöneticisi
  17. // @name:vi Trình Quản Lý Nền Tùy Chỉnh
  18. // @name:id Pengelola Latar Belakang Kustom
  19. // @name:bn কাস্টম ব্যাকগ্রাউন্ড ম্যানেজার
  20. // @name:pa ਕਸਟਮ ਬੈਕਗ੍ਰਾਊਂਡ ਮੈਨੇਜਰ
  21. // @name:ur حسب ضرورت پس منظر مینیجر
  22. // @name:ta தனிப்பயன் பின்னணி மேலாளர்
  23. // @name:fa مدیر پس‌زمینه سفارشی
  24. // @description:en Change background for websites [priority: manga-manhwa sites]
  25. // @description:es Cambiar el fondo de los sitios web [prioridad: sitios de manga-manhwa]
  26. // @description:zh 更改网站背景 [优先:漫画-漫画网站]
  27. // @description:hi वेबसाइटों के लिए पृष्ठभूमि बदलें [प्राथमिकता: मांगा-मनह्वा साइटें]
  28. // @description:ar تغيير الخلفية لمواقع الويب [الأولوية: مواقع المانجا-مانهوا]
  29. // @description:pt Alterar o plano de fundo dos sites [prioridade: sites de manga-manhwa]
  30. // @description:ru Изменение фона для веб-сайтов [приоритет: сайты манги-манхвы]
  31. // @description:ja ウェブサイトの背景を変更 [優先: マンガ・マンファサイト]
  32. // @description:de Hintergrund für Websites ändern [Priorität: Manga-Manhwa-Seiten]
  33. // @description:fr Modifier l'arrière-plan des sites Web [priorité : sites de manga-manhwa]
  34. // @description:it Cambia lo sfondo dei siti web [priorità: siti di manga-manhwa]
  35. // @description:ko 웹사이트 배경 변경 [우선 순위: 만화-만화 사이트]
  36. // @description:tr Web siteleri için arka plan değiştirme [öncelik: manga-manhwa siteleri]
  37. // @description:vi Thay đổi nền trang web [ưu tiên: trang manga-manhwa]
  38. // @description:id Mengubah latar belakang situs web [prioritas: situs manga-manhwa]
  39. // @description:bn ওয়েবসাইটের জন্য ব্যাকগ্রাউন্ড পরিবর্তন করুন [অগ্রাধিকার: মাঙ্গা-মানহওয়া সাইট]
  40. // @description:pa ਵੈੱਬਸਾਈਟਾਂ ਲਈ ਪਿਛੋਕੜ ਬਦਲੋ [ਤਰਜੀਹ: ਮੰਗਾ-ਮਾਨ੍ਹਵਾ ਸਾਈਟਾਂ]
  41. // @description:ur ویب سائٹس کے لیے پس منظر تبدیل کریں [ترجیح: مانگا-مانہوا سائٹس]
  42. // @description:ta இணையதளங்களுக்கு பின்னணியை மாற்றவும் [முன்னுரிமை: மங்கா-மன்வா தளங்கள்]
  43. // @description:fa تغییر پس‌زمینه برای وب‌سایت‌ها [اولویت: سایت‌های مانگا-مانهوا]
  44. // @author www.vebascans.net
  45. // @match https://*/*
  46. // @grant none
  47. // @icon https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi0QDJZNeXWcaD9lXWMN2yenYt5XGrqfPavkCFpWLe01CpSEsMn7IGpbOLqxEfjx4QUUi4wgTw0Kc7vP7FrKjPKpcaaCu1N6QRJzlZvS_Wwr2r3kA4l0-E5wl7xObsZchd8YNSxySFZATPAr2bnrkANBUrmy8Rpdexe-mxG8N6QDojEj0onaNNXF_6g-s/w800/logo.png
  48. // @description Web siteleri için arka plan değiştirme [öncelikli manga-manhwa siteleri]
  49. // ==/UserScript==
  50.  
  51. (function() {
  52. 'use strict';
  53.  
  54. // 1) SweetAlert2 kütüphanesini otomatik yükle:
  55. const script = document.createElement('script');
  56. script.src = 'https://cdn.jsdelivr.net/npm/sweetalert2@11';
  57. script.onload = main; // Kütüphane yüklendikten sonra main() fonksiyonunu çalıştır
  58. document.head.appendChild(script);
  59.  
  60. // 2) Tüm kodu main() içine alıyoruz:
  61. function main() {
  62.  
  63. /**************************************************************************
  64. * SweetAlert Tanımlaması
  65. **************************************************************************/
  66. const Toast = Swal.mixin({
  67. toast: true,
  68. position: "top",
  69. showConfirmButton: false,
  70. timer: 3000,
  71. timerProgressBar: true,
  72. didOpen: (toast) => {
  73. toast.onmouseenter = Swal.stopTimer;
  74. toast.onmouseleave = Swal.resumeTimer;
  75. }
  76. });
  77.  
  78. /**************************************************************************
  79. * 0) Sabitler
  80. **************************************************************************/
  81. const ACTIVE_KEY = 'VebaScans.net_custom_wp_active'; // Son seçilen veri (URL/Color)
  82. const HISTORY_KEY = 'VebaScans.net_custom_wp_history'; // Tüm geçmiş
  83. const SETTINGS_KEY = 'vebascans.net_custom_wp_settings'; // Arka plan ayarları
  84.  
  85. /**************************************************************************
  86. * 1) Local Storage Yardımcı Fonksiyonları
  87. **************************************************************************/
  88. function getActiveData() {
  89. try {
  90. const str = localStorage.getItem(ACTIVE_KEY);
  91. return str ? JSON.parse(str) : null;
  92. } catch (e) {
  93. return null;
  94. }
  95. }
  96.  
  97. function setActiveData(obj) {
  98. localStorage.setItem(ACTIVE_KEY, JSON.stringify(obj));
  99. applyActiveDataToBody(); // Aktif veri her değiştiğinde body'yi güncelle
  100. }
  101.  
  102. function removeActiveData() {
  103. localStorage.removeItem(ACTIVE_KEY);
  104. applyActiveDataToBody();
  105. }
  106.  
  107. function getHistoryData() {
  108. try {
  109. const str = localStorage.getItem(HISTORY_KEY);
  110. return str ? JSON.parse(str) : [];
  111. } catch (e) {
  112. return [];
  113. }
  114. }
  115.  
  116. function addToHistory(obj) {
  117. let history = getHistoryData();
  118.  
  119. // 1) Eğer geçmişte aynı öğe zaten varsa ekleme yapma
  120. const exists = history.some(item => item.type === obj.type && item.value === obj.value);
  121. if (exists) return; // Aynısı varsa, ekleme yapmadan çık
  122.  
  123. // 2) Yeni öğeyi ekle
  124. history.push(obj);
  125.  
  126. // 3) Aynı öğelerin tekrarını önlemek için filtrele (sadece bir tane kalacak)
  127. history = history.filter((item, index, self) =>
  128. index === self.findIndex(t => t.type === item.type && t.value === item.value)
  129. );
  130.  
  131. // 4) Güncellenmiş geçmişi kaydet
  132. localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
  133. }
  134.  
  135. // Geçmişten silme
  136. function removeFromHistory(obj) {
  137. let history = getHistoryData();
  138. history = history.filter(x => !(x.type === obj.type && x.value === obj.value));
  139. localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
  140. }
  141.  
  142. // Ayarlar
  143. function getSettings() {
  144. try {
  145. const str = localStorage.getItem(SETTINGS_KEY);
  146. return str ? JSON.parse(str) : {};
  147. } catch (e) {
  148. return {};
  149. }
  150. }
  151.  
  152. function setSettings(newSettings) {
  153. localStorage.setItem(SETTINGS_KEY, JSON.stringify(newSettings));
  154. }
  155.  
  156. /**************************************************************************
  157. * 2) BODY Arkaplanını Aktif Veriye (URL/Color) ve Ayarlara Göre Uygulama
  158. **************************************************************************/
  159. function applyActiveDataToBody() {
  160. const activeData = getActiveData();
  161. const settings = getSettings();
  162.  
  163. // Arkaplan tekrar ayarı (varsayılan = 'no-repeat')
  164. const bgRepeat = settings.bgRepeat || 'no-repeat';
  165. // Arkaplan sabit ayarı (varsayılan = 'scroll')
  166. const bgAttachment = settings.bgAttachment || 'scroll';
  167.  
  168. if (!activeData) {
  169. // Aktif bir şey yoksa varsayılan temize çek
  170. document.body.style.backgroundImage = '';
  171. document.body.style.backgroundColor = '';
  172. document.body.style.backgroundRepeat = '';
  173. document.body.style.backgroundAttachment = '';
  174. return;
  175. }
  176.  
  177. if (activeData.type === 'url') {
  178. // Body için arkaplan resmi
  179. document.body.style.backgroundImage = `url(${activeData.value})`;
  180. document.body.style.backgroundRepeat = bgRepeat;
  181. document.body.style.backgroundSize = 'cover';
  182. document.body.style.backgroundAttachment = bgAttachment;
  183. document.body.style.backgroundColor = '';
  184.  
  185. // .body-wrap için
  186. try {
  187. const bodyWrap = document.querySelector('body.text-ui-light .body-wrap');
  188. bodyWrap.style.backgroundImage = `url(${activeData.value})`;
  189. bodyWrap.style.backgroundRepeat = bgRepeat;
  190. bodyWrap.style.backgroundSize = 'cover';
  191. bodyWrap.style.backgroundAttachment = bgAttachment;
  192. bodyWrap.style.backgroundColor = '';
  193. } catch (error) { /* .body-wrap yoksa hata görmezden gel */ }
  194.  
  195. // .site-content için
  196. try {
  197. const sitecontent = document.querySelector('.site-content');
  198. sitecontent.style.backgroundImage = `url(${activeData.value})`;
  199. sitecontent.style.backgroundRepeat = bgRepeat;
  200. sitecontent.style.backgroundSize = 'cover';
  201. sitecontent.style.backgroundAttachment = bgAttachment;
  202. sitecontent.style.backgroundColor = '';
  203. } catch (error) { /* .site-content yoksa hata görmezden gel */ }
  204.  
  205. } else if (activeData.type === 'color') {
  206. // Body için arkaplan rengi
  207. document.body.style.backgroundImage = 'none';
  208. document.body.style.backgroundColor = activeData.value;
  209. document.body.style.backgroundRepeat = bgRepeat;
  210. document.body.style.backgroundAttachment = bgAttachment;
  211.  
  212. // .body-wrap için
  213. try {
  214. const bodyWrap = document.querySelector('body.text-ui-light .body-wrap');
  215. bodyWrap.style.backgroundImage = 'none';
  216. bodyWrap.style.backgroundColor = activeData.value;
  217. bodyWrap.style.backgroundRepeat = bgRepeat;
  218. bodyWrap.style.backgroundAttachment = bgAttachment;
  219. } catch (error) { /* .body-wrap yoksa hata görmezden gel */ }
  220.  
  221. // .site-content için
  222. try {
  223. const sitecontent = document.querySelector('.site-content');
  224. sitecontent.style.backgroundImage = 'none';
  225. sitecontent.style.backgroundColor = activeData.value;
  226. sitecontent.style.backgroundRepeat = bgRepeat;
  227. sitecontent.style.backgroundAttachment = bgAttachment;
  228. } catch (error) { /* .site-content yoksa hata görmezden gel */ }
  229. }
  230. }
  231.  
  232. /**************************************************************************
  233. * 3) MODAL Arayüzü Oluşturma
  234. **************************************************************************/
  235. let modalOverlay, modalContent;
  236.  
  237. window.addEventListener('load', () => {
  238. createModal();
  239. createToggleShortcut(); // F7 ile aç/kapa
  240. applyActiveDataToBody(); // Sayfa açıldığında kaydedilmiş aktif veriyi uygula
  241. });
  242.  
  243. // F7 ile modal aç/kapa
  244. function createToggleShortcut() {
  245. window.addEventListener('keydown', (e) => {
  246. if (e.key === 'F7') {
  247. toggleModal();
  248. }
  249. });
  250. }
  251.  
  252. function toggleModal(forceOpen) {
  253. const isHidden = (modalOverlay.style.display === 'none');
  254. if (forceOpen === true) {
  255. showModal();
  256. } else if (forceOpen === false) {
  257. hideModal();
  258. } else {
  259. if (isHidden) showModal(); else hideModal();
  260. }
  261. }
  262.  
  263. function showModal() {
  264. modalOverlay.style.display = 'block';
  265. refreshHistoryList();
  266. refreshActiveLabel();
  267. refreshSettingsUI();
  268. applyModalTheme(); // Tema ayarını modal açıldığında uygula
  269. }
  270.  
  271. function hideModal() {
  272. modalOverlay.style.display = 'none';
  273. }
  274.  
  275. function createModal() {
  276. // (1) Overlay
  277. modalOverlay = document.createElement('div');
  278. Object.assign(modalOverlay.style, {
  279. display: 'none',
  280. position: 'fixed',
  281. top: '0',
  282. left: '0',
  283. width: '100%',
  284. height: '100%',
  285. backgroundColor: 'rgba(0,0,0,0.5)',
  286. zIndex: '99999',
  287. color: '#000'
  288. });
  289. document.body.appendChild(modalOverlay);
  290.  
  291. // (2) İçerik
  292. modalContent = document.createElement('div');
  293. Object.assign(modalContent.style, {
  294. position: 'absolute',
  295. top: '50%',
  296. left: '50%',
  297. transform: 'translate(-50%, -50%)',
  298. width: '400px',
  299. backgroundColor: '#fff',
  300. padding: '20px',
  301. borderTopLeftRadius: '15px',
  302. borderBottomRightRadius: '15px',
  303. border: '3px solid black',
  304. minHeight: '450px',
  305. fontFamily: 'Arial, sans-serif',
  306. fontSize: '14px',
  307. fontWeight: 'normal',
  308. color: '#000',
  309. });
  310. modalOverlay.appendChild(modalContent);
  311.  
  312. // (3) Logo
  313. const img = document.createElement('img');
  314. img.src = 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi0QDJZNeXWcaD9lXWMN2yenYt5XGrqfPavkCFpWLe01CpSEsMn7IGpbOLqxEfjx4QUUi4wgTw0Kc7vP7FrKjPKpcaaCu1N6QRJzlZvS_Wwr2r3kA4l0-E5wl7xObsZchd8YNSxySFZATPAr2bnrkANBUrmy8Rpdexe-mxG8N6QDojEj0onaNNXF_6g-s/w800/logo.png';
  315. img.alt = 'Logo';
  316. Object.assign(img.style, {
  317. width: '130px',
  318. position: 'absolute',
  319. top: '0',
  320. right: '50%',
  321. transform: 'translate(50%, -50%)'
  322. });
  323. modalContent.appendChild(img);
  324.  
  325. // (4) Başlık
  326. const header = document.createElement('h3');
  327. header.innerHTML = '<a href="https://www.vebascans.net/" style="color: #b83eae;font-weight: 500;text-decoration: none;font-family: fantasy;text-shadow: 0 0 3px #b83eae;letter-spacing: 1px;">Vebascans</a> - Custom Background';
  328. header.style.margin = '0 0 10px 0';
  329. header.style.color = 'black';
  330. header.style.marginTop = '45px';
  331. modalContent.appendChild(header);
  332.  
  333. // (5) Kapat butonu
  334. const closeBtn = document.createElement('button');
  335. closeBtn.innerHTML = `
  336. <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  337. <g fill="none" fill-rule="evenodd">
  338. <path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/>
  339. <path fill="currentColor" d="m12 14.122l5.303 5.303a1.5 1.5 0 0 0 2.122-2.122L14.12 12l5.304-5.303a1.5 1.5 0 1 0-2.122-2.121L12 9.879L6.697 4.576a1.5 1.5 0 1 0-2.122 2.12L9.88 12l-5.304 5.304a1.5 1.5 0 1 0 2.122 2.12z"/>
  340. </g>
  341. </svg>`;
  342. Object.assign(closeBtn.style, {
  343. position: 'absolute',
  344. top: '10px',
  345. right: '10px',
  346. border: 'none',
  347. background: 'transparent',
  348. cursor: 'pointer',
  349. color: 'black'
  350. });
  351. closeBtn.onclick = () => hideModal();
  352. modalContent.appendChild(closeBtn);
  353.  
  354. // (6) Seçim Menüsü (URL mi Renk mi)
  355. const selectDiv = document.createElement('div');
  356. Object.assign(selectDiv.style, {
  357. display: 'flex',
  358. flexDirection: 'row',
  359. gap: '5px',
  360. marginBottom: '10px'
  361. });
  362. modalContent.appendChild(selectDiv);
  363.  
  364. const selectLabel = document.createElement('label');
  365. selectLabel.textContent = 'Seçim: ';
  366. selectLabel.style.display = 'flex';
  367. selectLabel.style.alignItems = 'center';
  368. selectDiv.appendChild(selectLabel);
  369.  
  370. const selectInput = document.createElement('select');
  371. selectInput.id = 'typeSelect';
  372. selectInput.style.background ='white';
  373. selectInput.style.border ='2px solid black';
  374. selectInput.style.borderRadius ='3px';
  375. selectInput.style.color = 'black';
  376. const optUrl = new Option('URL', 'url');
  377. const optColor = new Option('Renk', 'color');
  378. selectInput.add(optUrl);
  379. selectInput.add(optColor);
  380. selectDiv.appendChild(selectInput);
  381.  
  382. // (7) URL input
  383. const urlInput = document.createElement('input');
  384. urlInput.type = 'text';
  385. urlInput.id = 'urlInput';
  386. urlInput.placeholder = 'Görsel URL giriniz...';
  387. urlInput.style.background ='transparent';
  388. urlInput.style.border ='2px solid black';
  389. urlInput.style.borderRadius ='3px';
  390. selectDiv.appendChild(urlInput);
  391.  
  392. // (8) Color input
  393. const colorInput = document.createElement('input');
  394. colorInput.type = 'color';
  395. colorInput.id = 'colorInput';
  396. colorInput.value = '#000000';
  397. colorInput.style.width = '50px';
  398. colorInput.style.height = '30px';
  399. colorInput.style.display = 'none';
  400. selectDiv.appendChild(colorInput);
  401.  
  402. // Seçim değişince hangi input görünsün?
  403. selectInput.addEventListener('change', () => {
  404. if (selectInput.value === 'url') {
  405. urlInput.style.display = 'inline-block';
  406. colorInput.style.display = 'none';
  407. } else {
  408. urlInput.style.display = 'none';
  409. colorInput.style.display = 'inline-block';
  410. }
  411. });
  412.  
  413. // (9) Aktar butonu
  414. const aktarBtn = document.createElement('button');
  415. aktarBtn.textContent = 'Aktar';
  416. aktarBtn.style.marginLeft = '5px';
  417. aktarBtn.style.padding = '5px 10px';
  418. aktarBtn.style.cursor = 'pointer';
  419. aktarBtn.style.color = 'black';
  420. aktarBtn.style.border ='2px solid black';
  421. aktarBtn.style.borderRadius ='3px';
  422. aktarBtn.style.background = 'transparent';
  423. selectDiv.appendChild(aktarBtn);
  424.  
  425. aktarBtn.onclick = () => {
  426. const currentType = selectInput.value; // 'url' | 'color'
  427. let currentValue = '';
  428. if (currentType === 'url') {
  429. currentValue = urlInput.value.trim();
  430. if (!currentValue) {
  431. Toast.fire({ icon: 'error', title: 'Lütfen bir URL girin.' });
  432. return;
  433. }
  434. } else {
  435. currentValue = colorInput.value; // #rrggbb
  436. if (!currentValue) {
  437. Toast.fire({ icon: 'error', title: 'Lütfen bir renk seçin.' });
  438. return;
  439. }
  440. }
  441.  
  442. // Yeni aktif obje
  443. const newActiveObj = { type: currentType, value: currentValue };
  444. setActiveData(newActiveObj);
  445. addToHistory(newActiveObj);
  446.  
  447. refreshHistoryList();
  448. refreshActiveLabel();
  449.  
  450. // URL tipini kullandıysa inputu temizleyelim
  451. if (currentType === 'url') {
  452. urlInput.value = '';
  453. }
  454. Toast.fire({ icon: 'success', title: 'Yeni aktif değer atandı ve body arkaplanı güncellendi!' });
  455. };
  456.  
  457. // (10) Tekrar / Tek Sefer AYARI
  458. const repeatDiv = document.createElement('div');
  459. repeatDiv.style.margin = '10px 0';
  460. repeatDiv.style.display = 'flex';
  461. repeatDiv.style.flexDirection = 'row';
  462. repeatDiv.style.gap = '10px';
  463. modalContent.appendChild(repeatDiv);
  464.  
  465. const repeatLabel = document.createElement('span');
  466. repeatLabel.textContent = 'Arkaplan Tekrarı:';
  467. repeatLabel.style.alignSelf = 'center';
  468. repeatDiv.appendChild(repeatLabel);
  469.  
  470. const labelRepeat = document.createElement('label');
  471. const radioRepeat = document.createElement('input');
  472. radioRepeat.type = 'radio';
  473. radioRepeat.name = 'bgRepeat';
  474. radioRepeat.value = 'repeat';
  475. radioRepeat.style.marginRight = '5px';
  476. labelRepeat.appendChild(radioRepeat);
  477. labelRepeat.appendChild(document.createTextNode('Tekrarlı'));
  478. repeatDiv.appendChild(labelRepeat);
  479.  
  480. const labelNoRepeat = document.createElement('label');
  481. const radioNoRepeat = document.createElement('input');
  482. radioNoRepeat.type = 'radio';
  483. radioNoRepeat.name = 'bgRepeat';
  484. radioNoRepeat.value = 'no-repeat';
  485. radioNoRepeat.style.marginRight = '5px';
  486. labelNoRepeat.appendChild(radioNoRepeat);
  487. labelNoRepeat.appendChild(document.createTextNode('Tek Sefer'));
  488. repeatDiv.appendChild(labelNoRepeat);
  489.  
  490. [radioRepeat, radioNoRepeat].forEach(radio => {
  491. radio.addEventListener('change', () => {
  492. const newVal = radio.value; // 'repeat' | 'no-repeat'
  493. const s = getSettings();
  494. s.bgRepeat = newVal;
  495. setSettings(s);
  496. applyActiveDataToBody();
  497. });
  498. });
  499.  
  500. // (10b) Arkaplan Sabit AYARI
  501. const attachDiv = document.createElement('div');
  502. attachDiv.style.margin = '10px 0';
  503. attachDiv.style.display = 'flex';
  504. attachDiv.style.flexDirection = 'row';
  505. attachDiv.style.gap = '10px';
  506. modalContent.appendChild(attachDiv);
  507.  
  508. const attachLabel = document.createElement('span');
  509. attachLabel.textContent = 'Arkaplan Sabitliği:';
  510. attachLabel.style.alignSelf = 'center';
  511. attachDiv.appendChild(attachLabel);
  512.  
  513. const labelFixed = document.createElement('label');
  514. const radioFixed = document.createElement('input');
  515. radioFixed.type = 'radio';
  516. radioFixed.name = 'bgAttach';
  517. radioFixed.value = 'fixed';
  518. radioFixed.style.marginRight = '5px';
  519. labelFixed.appendChild(radioFixed);
  520. labelFixed.appendChild(document.createTextNode('Sabit (Fixed)'));
  521. attachDiv.appendChild(labelFixed);
  522.  
  523. const labelScroll = document.createElement('label');
  524. const radioScroll = document.createElement('input');
  525. radioScroll.type = 'radio';
  526. radioScroll.name = 'bgAttach';
  527. radioScroll.value = 'scroll';
  528. radioScroll.style.marginRight = '5px';
  529. labelScroll.appendChild(radioScroll);
  530. labelScroll.appendChild(document.createTextNode('Kaydır (Scroll)'));
  531. attachDiv.appendChild(labelScroll);
  532.  
  533. [radioFixed, radioScroll].forEach(radio => {
  534. radio.addEventListener('change', () => {
  535. const newVal = radio.value; // 'fixed' | 'scroll'
  536. const s = getSettings();
  537. s.bgAttachment = newVal;
  538. setSettings(s);
  539. applyActiveDataToBody();
  540. });
  541. });
  542.  
  543. // (11) Aktif Veriyi Sil
  544. const removeActiveBtn = document.createElement('button');
  545. removeActiveBtn.textContent = 'Devre dışı bırak';
  546. removeActiveBtn.style.marginBottom = '10px';
  547. removeActiveBtn.style.padding = '5px 10px';
  548. removeActiveBtn.style.cursor = 'pointer';
  549. removeActiveBtn.style.color = 'black';
  550. removeActiveBtn.style.background = 'transparent';
  551. removeActiveBtn.style.border ='2px solid black';
  552. removeActiveBtn.style.borderRadius ='3px';
  553. modalContent.appendChild(removeActiveBtn);
  554.  
  555. removeActiveBtn.onclick = () => {
  556. removeActiveData();
  557. refreshHistoryList();
  558. refreshActiveLabel();
  559. Toast.fire({ icon: 'info', title: 'Aktif veri silindi. Arkaplan temizlendi.' });
  560. };
  561.  
  562. // (12) Şu anda aktif veriyi gösteren label
  563. const activeDiv = document.createElement('div');
  564. activeDiv.id = 'activeDiv';
  565. activeDiv.style.marginTop = '10px';
  566. modalContent.appendChild(activeDiv);
  567.  
  568. // (13) Geçmiş Başlık
  569. const historyTitle = document.createElement('h4');
  570. historyTitle.textContent = 'Geçmiş';
  571. historyTitle.style.margin = '10px 0 5px 0';
  572. modalContent.appendChild(historyTitle);
  573.  
  574. // (14) Geçmiş Container
  575. const historyContainer = document.createElement('div');
  576. historyContainer.id = 'historyContainer';
  577. historyContainer.style.maxHeight = '200px';
  578. historyContainer.style.overflowY = 'auto';
  579. historyContainer.style.border = '1px solid #ccc';
  580. historyContainer.style.padding = '5px';
  581. modalContent.appendChild(historyContainer);
  582.  
  583. // Yedekleme (Dışa/İçe Aktar)
  584. const importExportTitle = document.createElement('h4');
  585. importExportTitle.textContent = 'Yedekleme';
  586. importExportTitle.style.margin = '10px 0 5px 0';
  587. modalContent.appendChild(importExportTitle);
  588.  
  589. const exportBtn = document.createElement('button');
  590. exportBtn.textContent = 'Dışa Aktar (JSON)';
  591. exportBtn.style.padding = '5px 10px';
  592. exportBtn.style.cursor = 'pointer';
  593. exportBtn.style.color = 'black';
  594. exportBtn.style.background = 'transparent';
  595. exportBtn.style.border = '2px solid black';
  596. exportBtn.style.borderRadius = '3px';
  597. exportBtn.style.marginRight = '10px';
  598. modalContent.appendChild(exportBtn);
  599.  
  600. exportBtn.onclick = () => {
  601. exportDataAsJson();
  602. };
  603.  
  604. const importBtn = document.createElement('button');
  605. importBtn.textContent = 'İçe Aktar (JSON)';
  606. importBtn.style.padding = '5px 10px';
  607. importBtn.style.cursor = 'pointer';
  608. importBtn.style.color = 'black';
  609. importBtn.style.background = 'transparent';
  610. importBtn.style.border = '2px solid black';
  611. importBtn.style.borderRadius = '3px';
  612. modalContent.appendChild(importBtn);
  613.  
  614. const importInput = document.createElement('input');
  615. importInput.type = 'file';
  616. importInput.accept = 'application/json';
  617. importInput.style.display = 'none';
  618. modalContent.appendChild(importInput);
  619.  
  620. importBtn.addEventListener('click', () => {
  621. importInput.click(); // Dosya seçme penceresini aç
  622. });
  623.  
  624. importInput.addEventListener('change', () => {
  625. if (importInput.files && importInput.files[0]) {
  626. importDataFromJson(importInput.files[0]);
  627. }
  628. });
  629.  
  630. /**************************************************************************
  631. * _Eklenen Kod Başlangıcı_ (Tema Ayarı)
  632. **************************************************************************/
  633. // Tema AYARI için radyo seçenekleri
  634. const themeDiv = document.createElement('div');
  635. themeDiv.style.marginTop = '15px';
  636. themeDiv.style.display = 'flex';
  637. themeDiv.style.flexDirection = 'row';
  638. themeDiv.style.gap = '10px';
  639. modalContent.appendChild(themeDiv);
  640.  
  641. const themeLabel = document.createElement('span');
  642. themeLabel.textContent = 'Modal Tema:';
  643. themeLabel.style.alignSelf = 'center';
  644. themeDiv.appendChild(themeLabel);
  645.  
  646. const labelLight = document.createElement('label');
  647. const radioLight = document.createElement('input');
  648. radioLight.type = 'radio';
  649. radioLight.name = 'modalTheme';
  650. radioLight.value = 'light';
  651. radioLight.style.marginRight = '5px';
  652. labelLight.appendChild(radioLight);
  653. labelLight.appendChild(document.createTextNode('Aydınlık'));
  654. themeDiv.appendChild(labelLight);
  655.  
  656. const labelDark = document.createElement('label');
  657. const radioDark = document.createElement('input');
  658. radioDark.type = 'radio';
  659. radioDark.name = 'modalTheme';
  660. radioDark.value = 'dark';
  661. radioDark.style.marginRight = '5px';
  662. labelDark.appendChild(radioDark);
  663. labelDark.appendChild(document.createTextNode('Karanlık'));
  664. themeDiv.appendChild(labelDark);
  665.  
  666. // Radyo değişimiyle tema ayarını kaydetme
  667. [radioLight, radioDark].forEach(radio => {
  668. radio.addEventListener('change', () => {
  669. const newVal = radio.value; // 'light' | 'dark'
  670. const s = getSettings();
  671. s.theme = newVal;
  672. setSettings(s);
  673. applyModalTheme(); // Tema uygulansın
  674. });
  675. });
  676.  
  677. const support = document.createElement('div');
  678. support.innerHTML = `
  679. <h3 style="color: black; margin: 4px 0;">Destek;</h3>
  680. <a href="https://www.vebascans.net/discord" style="color: black;align-items: center; display: flex; text-decoration: none;">
  681. <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  682. <g fill="currentColor" fill-opacity="0">
  683. <circle cx="9" cy="12" r="1.5">
  684. <animate fill="freeze" attributeName="fill-opacity" begin="1.3s" dur="0.15s" values="0;1"/>
  685. </circle>
  686. <circle cx="15" cy="12" r="1.5">
  687. <animate fill="freeze" attributeName="fill-opacity" begin="1.45s" dur="0.15s" values="0;1"/>
  688. </circle>
  689. <path d="M5 5l7 0.2l7 -0.2l3 10l-3 3.4h-14l-3.5 -3.4l3.5 -10Z">
  690. <animate fill="freeze" attributeName="fill-opacity" begin="1.7s" dur="0.15s" values="0;0.3"/>
  691. </path>
  692. </g>
  693. <g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
  694. <path stroke-dasharray="32" stroke-dashoffset="32" d="M12 6h2l1 -2c0 0 2.5 0.5 4 1.5c3.53 2.35 3 9.5 3 10.5c-1.33 2.17 -5.5 3.5 -5.5 3.5l-1 -2M12 6h-2l-0.97 -2c0 0 -2.5 0.5 -4 1.5c-3.53 2.35 -3 9.5 -3 10.5c1.33 2.17 5.5 3.5 5.5 3.5l1 -2">
  695. <animate fill="freeze" attributeName="stroke-dashoffset" dur="0.7s" values="32;0"/>
  696. </path>
  697. <path stroke-dasharray="16" stroke-dashoffset="16" d="M5.5 16c5 2.5 8 2.5 13 0">
  698. <animate fill="freeze" attributeName="stroke-dashoffset" begin="0.8s" dur="0.4s" values="16;0"/>
  699. </path>
  700. </g>
  701. </svg>
  702. </a>`;
  703. support.style.marginTop = '15px';
  704. support.style.display = 'flex';
  705. support.style.flexDirection = 'row';
  706. support.style.gap = '10px';
  707. modalContent.appendChild(support);
  708. }
  709.  
  710. /**************************************************************************
  711. * 4) Geçmiş & Aktif Listeyi Güncelleme
  712. **************************************************************************/
  713. function refreshHistoryList() {
  714. const historyContainer = document.getElementById('historyContainer');
  715. if (!historyContainer) return;
  716.  
  717. historyContainer.innerHTML = '';
  718.  
  719. const historyData = getHistoryData();
  720. const activeData = getActiveData(); // {type:'...', value:'...'}
  721.  
  722. historyData.forEach((item) => {
  723. const row = document.createElement('div');
  724. row.style.display = 'flex';
  725. row.style.alignItems = 'center';
  726. row.style.marginBottom = '8px';
  727. row.style.cursor = 'pointer';
  728. row.style.justifyContent = 'space-between';
  729.  
  730. const leftPart = document.createElement('div');
  731. leftPart.style.display = 'flex';
  732. leftPart.style.alignItems = 'center';
  733. leftPart.style.gap = '8px';
  734.  
  735. // URL ise küçük görsel
  736. if (item.type === 'url') {
  737. const imgThumb = document.createElement('img');
  738. imgThumb.src = item.value;
  739. imgThumb.alt = 'Görsel';
  740. imgThumb.style.width = '30px';
  741. imgThumb.style.height = '30px';
  742. imgThumb.style.objectFit = 'cover';
  743. leftPart.appendChild(imgThumb);
  744.  
  745. const label = document.createElement('span');
  746. label.textContent = 'URL';
  747. leftPart.appendChild(label);
  748.  
  749. } else if (item.type === 'color') {
  750. // Renk ise kutu
  751. const colorBox = document.createElement('span');
  752. colorBox.style.display = 'inline-block';
  753. colorBox.style.width = '30px';
  754. colorBox.style.height = '30px';
  755. colorBox.style.backgroundColor = item.value;
  756. colorBox.style.border = '1px solid #000';
  757. leftPart.appendChild(colorBox);
  758.  
  759. const label = document.createElement('span');
  760. label.textContent = item.value;
  761. leftPart.appendChild(label);
  762. }
  763.  
  764. // Aktif mi?
  765. if (activeData && activeData.type === item.type && activeData.value === item.value) {
  766. const activeSpan = document.createElement('span');
  767. activeSpan.textContent = ' (Aktif)';
  768. activeSpan.style.color = 'green';
  769. leftPart.appendChild(activeSpan);
  770. }
  771.  
  772. // Tıklayınca bu itemi aktif yap
  773. leftPart.addEventListener('click', () => {
  774. setActiveData(item);
  775. refreshHistoryList();
  776. refreshActiveLabel();
  777. Toast.fire({ icon: 'success', title: 'Aktif değer güncellendi!' });
  778. });
  779.  
  780. // Sağ kısma "Geçmişten Sil" butonu
  781. const rightPart = document.createElement('button');
  782. rightPart.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m20 9l-1.995 11.346A2 2 0 0 1 16.035 22h-8.07a2 2 0 0 1-1.97-1.654L4 9m17-3h-5.625M3 6h5.625m0 0V4a2 2 0 0 1 2-2h2.75a2 2 0 0 1 2 2v2m-6.75 0h6.75"/></svg>';
  783. rightPart.style.border ='2px solid black';
  784. rightPart.style.color= 'black'
  785. rightPart.style.borderRadius ='3px';
  786. rightPart.style.background = 'transparent';
  787. rightPart.style.padding = '3px 5px';
  788. rightPart.style.cursor = 'pointer';
  789.  
  790. rightPart.addEventListener('click', (e) => {
  791. e.stopPropagation(); // Aktif yapma tıklamasını engelle
  792.  
  793. // Aktif veriyi al
  794. const activeData = getActiveData();
  795.  
  796. // Eğer silinmek istenen veri aktif veriyle eşleşiyorsa, işlemi durdur
  797. if (activeData && activeData.type === item.type && activeData.value === item.value) {
  798. Toast.fire({ icon: 'warning', title: 'Aktif olan bir veriyi silemezsiniz!' });
  799. return; // İşlemi durdur
  800. }
  801.  
  802. // Eğer aktif veri değilse, geçmişten sil
  803. removeFromHistory(item);
  804. refreshHistoryList();
  805. Toast.fire({ icon: 'info', title: 'Geçmişten silindi.' });
  806. });
  807.  
  808. row.appendChild(leftPart);
  809. row.appendChild(rightPart);
  810. historyContainer.appendChild(row);
  811. });
  812. }
  813.  
  814. function refreshActiveLabel() {
  815. const activeDiv = document.getElementById('activeDiv');
  816. if (!activeDiv) return;
  817.  
  818. const activeData = getActiveData();
  819. if (!activeData) {
  820. activeDiv.textContent = 'Şu anda aktif bir değer yok.';
  821. } else {
  822. if (activeData.type === 'url') {
  823. activeDiv.innerHTML = `
  824. Aktif: URL
  825. <img src="${activeData.value}"
  826. alt="Aktif Görsel"
  827. style="width: 100px; height: auto; object-fit: cover; margin-left:5px;"/>
  828. `;
  829. } else {
  830. activeDiv.innerHTML = `
  831. Aktif: Renk
  832. <span style="display:inline-block; width:20px; height:20px;
  833. background-color:${activeData.value};
  834. border:1px solid #000; vertical-align:middle;">
  835. </span>
  836. ${activeData.value}
  837. `;
  838. }
  839. }
  840. }
  841.  
  842. /**************************************************************************
  843. * 5) Arkaplan Ayarı (Tekrar / Tek Sefer / Sabit) Radyo Butonlarını Güncelleme
  844. **************************************************************************/
  845. function refreshSettingsUI() {
  846. const settings = getSettings();
  847. const bgRepeat = settings.bgRepeat || 'no-repeat'; // Varsayılan no-repeat
  848. const bgAttach = settings.bgAttachment || 'scroll'; // Varsayılan scroll
  849.  
  850. // Tekrar radyo
  851. const radiosRepeat = document.getElementsByName('bgRepeat');
  852. radiosRepeat.forEach(radio => {
  853. radio.checked = (radio.value === bgRepeat);
  854. });
  855.  
  856. // Sabit/Kaydır radyo
  857. const radiosAttach = document.getElementsByName('bgAttach');
  858. radiosAttach.forEach(radio => {
  859. radio.checked = (radio.value === bgAttach);
  860. });
  861.  
  862. // _Eklenen Kod: Modal Tema radyo
  863. const theme = settings.theme || 'light'; // Varsayılan 'light'
  864. const radiosTheme = document.getElementsByName('modalTheme');
  865. radiosTheme.forEach(radio => {
  866. radio.checked = (radio.value === theme);
  867. });
  868. }
  869.  
  870. // Tema uygulama fonksiyonu
  871. function applyModalTheme() {
  872. const settings = getSettings();
  873. const theme = settings.theme || 'light';
  874.  
  875. if (theme === 'dark') {
  876. // Modal ana gövde
  877. modalContent.style.backgroundColor = '#070707';
  878. modalContent.style.color = 'white';
  879. modalContent.style.border = '2px solid white';
  880.  
  881. // Tüm alt öğeleri tarayalım:
  882. const allElements = modalContent.querySelectorAll('*');
  883. allElements.forEach(el => {
  884. // Eğer siyah sınır varsa beyaza çevir
  885. if (el.style.border === '2px solid black') {
  886. el.style.border = '2px solid white';
  887. }
  888. // Yazı rengi siyahsa beyaza çevir
  889. if (el.style.color === 'black') {
  890. el.style.color = 'white';
  891. }
  892. // Arka plan beyaz veya 'transparent' ise #070707 yap
  893. const bg = el.style.backgroundColor || el.style.background;
  894. if (bg === 'white' || bg === 'transparent') {
  895. el.style.backgroundColor = '#070707';
  896. }
  897. });
  898.  
  899. } else {
  900. // Light (aydınlık) tema için varsayılanlar
  901. modalContent.style.backgroundColor = '#fff';
  902. modalContent.style.color = 'black';
  903. modalContent.style.border = '2px solid black';
  904.  
  905. // Tekrar tüm alt öğeleri dolaşıp varsayılan değerlere çekebilirsiniz
  906. const allElements = modalContent.querySelectorAll('*');
  907. allElements.forEach(el => {
  908. // Siyah kenarlık
  909. if (el.style.border === '2px solid white') {
  910. el.style.border = '2px solid black';
  911. }
  912. // Yazı rengi beyaz ise siyaha çevir
  913. if (el.style.color === 'white') {
  914. el.style.color = 'black';
  915. }
  916. // Arka plan koyu ise beyaza veya transparent’e döndürebilirsiniz
  917. const bg = el.style.backgroundColor || el.style.background;
  918. if (bg === 'rgb(7, 7, 7)' || bg === '#070707') {
  919. el.style.backgroundColor = 'white';
  920. }
  921. });
  922. }
  923. }
  924.  
  925. // Dışa Aktar (JSON olarak)
  926. function exportDataAsJson() {
  927. // Tek bir obje içine aktif, geçmiş ve ayarları al
  928. const data = {
  929. active: getActiveData(),
  930. history: getHistoryData(),
  931. settings: getSettings()
  932. };
  933. const jsonStr = JSON.stringify(data, null, 2);
  934.  
  935. // Dosya oluşturup otomatik indirme linki
  936. const blob = new Blob([jsonStr], { type: 'application/json' });
  937. const url = URL.createObjectURL(blob);
  938. const a = document.createElement('a');
  939. a.href = url;
  940. a.download = 'Vebascans_CustomBackground.json';
  941. document.body.appendChild(a);
  942. a.click();
  943. a.remove();
  944. URL.revokeObjectURL(url);
  945.  
  946. Toast.fire({ icon: 'success', title: 'Veriler JSON formatında indirildi!' });
  947. }
  948.  
  949. // İçe Aktar (JSON dosyasından)
  950. function importDataFromJson(file) {
  951. const reader = new FileReader();
  952. reader.onload = (e) => {
  953. try {
  954. const imported = JSON.parse(e.target.result);
  955.  
  956. // Dosyada hangi veriler varsa alıp localStorage'a yazalım
  957. if (imported.active) {
  958. localStorage.setItem(ACTIVE_KEY, JSON.stringify(imported.active));
  959. }
  960. if (imported.history) {
  961. localStorage.setItem(HISTORY_KEY, JSON.stringify(imported.history));
  962. }
  963. if (imported.settings) {
  964. localStorage.setItem(SETTINGS_KEY, JSON.stringify(imported.settings));
  965. }
  966.  
  967. // Yeniden uygula ve arayüzü tazele
  968. applyActiveDataToBody();
  969. refreshHistoryList();
  970. refreshActiveLabel();
  971. refreshSettingsUI();
  972. applyModalTheme();
  973.  
  974. Toast.fire({ icon: 'success', title: 'JSON verileri başarıyla içe aktarıldı!' });
  975. } catch (error) {
  976. Toast.fire({ icon: 'error', title: 'Geçersiz JSON dosyası veya okuma hatası!' });
  977. }
  978. };
  979. reader.readAsText(file);
  980. }
  981.  
  982. } // main() sonu
  983.  
  984. })(); // IIFE sonu