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

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址