Mudanças entre as edições de "Widget:C.Background"
Ir para navegação
Ir para pesquisar
(Criou página com '<!-- BACKGROUND SYSTEM --> <script> (function () { 'use strict'; const { filePathURL } = window.__CBase || {}; function buildBgURL(fileName) {...') |
m |
||
| Linha 1: | Linha 1: | ||
<!-- BACKGROUND SYSTEM --> | <!-- =========================== | ||
BACKGROUND SYSTEM (com cache persistente) | |||
=========================== --> | |||
<script> | <script> | ||
/** | |||
* @typedef {Object} MediaWiki | |||
* @property {Object} util | |||
* @property {Function} util.wikiScript | |||
* @property {Function} util.wikiUrlencode | |||
* @property {Object} config | |||
* @property {Function} config.get | |||
*/ | |||
// @ts-ignore - MediaWiki global | |||
var mw = window.mw || {}; | |||
(function () { | (function () { | ||
/** | |||
* Builds a MediaWiki file URL from a filename | |||
* @param {string} fileName - The filename (with or without "Arquivo:" prefix) | |||
* @returns {string} The full URL to the file | |||
*/ | |||
function buildBgURL(fileName) { | function buildBgURL(fileName) { | ||
if (!fileName) return ''; | if (!fileName) return ''; | ||
var base = (window.mw && mw.util && typeof mw.util.wikiScript === 'function') | |||
? mw.util.wikiScript() | ? mw.util.wikiScript() | ||
: (window.mw && | : (window.mw && mw.config ? (mw.config.get('wgScript') || '/index.php') : '/index.php'); | ||
var path = 'Especial:FilePath/' + fileName.replace(/^Arquivo:|^File:/, ''); | |||
if (window.mw && mw.util && typeof mw.util.wikiUrlencode === 'function') { | if (window.mw && mw.util && typeof mw.util.wikiUrlencode === 'function') { | ||
return base + '?title=' + mw.util.wikiUrlencode(path); | return base + '?title=' + mw.util.wikiUrlencode(path); | ||
| Linha 19: | Linha 33: | ||
} | } | ||
/** | |||
* Sistema de cache persistente usando IndexedDB | |||
*/ | |||
var BgCache = (function () { | |||
var DB_NAME = 'character-bg-cache'; | |||
var DB_VERSION = 1; | |||
var STORE_NAME = 'backgrounds'; | |||
var db = null; | |||
/** | |||
* Inicializa o banco de dados IndexedDB | |||
*/ | |||
function initDB() { | |||
return new Promise(function (resolve, reject) { | |||
if (db) { | |||
resolve(db); | |||
return; | |||
} | |||
if (!window.indexedDB) { | |||
reject(new Error('IndexedDB não disponível')); | |||
return; | |||
} | |||
var request = indexedDB.open(DB_NAME, DB_VERSION); | |||
request.onerror = function () { | |||
reject(request.error); | |||
}; | |||
request.onsuccess = function () { | |||
db = request.result; | |||
resolve(db); | |||
}; | |||
request.onupgradeneeded = function (event) { | |||
var database = event.target.result; | |||
if (!database.objectStoreNames.contains(STORE_NAME)) { | |||
database.createObjectStore(STORE_NAME); | |||
} | |||
}; | |||
}); | |||
} | |||
/** | |||
* Obtém imagem do cache | |||
* @param {string} url - URL da imagem | |||
* @returns {Promise<string|null>} URL do blob ou null se não estiver em cache | |||
*/ | |||
function get(url) { | |||
return initDB().then(function (database) { | |||
return new Promise(function (resolve, reject) { | |||
var transaction = database.transaction([STORE_NAME], 'readonly'); | |||
var store = transaction.objectStore(STORE_NAME); | |||
var request = store.get(url); | |||
request.onsuccess = function () { | |||
var blob = request.result; | |||
if (blob && blob instanceof Blob) { | |||
var blobUrl = URL.createObjectURL(blob); | |||
resolve(blobUrl); | |||
} else { | |||
resolve(null); | |||
} | |||
}; | |||
request.onerror = function () { | |||
reject(request.error); | |||
}; | |||
}); | |||
}).catch(function () { | |||
return Promise.resolve(null); | |||
}); | |||
} | |||
/** | |||
* Salva imagem no cache | |||
* @param {string} url - URL da imagem | |||
* @param {Blob} blob - Blob da imagem | |||
*/ | |||
function set(url, blob) { | |||
initDB().then(function (database) { | |||
var transaction = database.transaction([STORE_NAME], 'readwrite'); | |||
var store = transaction.objectStore(STORE_NAME); | |||
store.put(blob, url); | |||
}).catch(function () { | |||
// Falha silenciosa - cache opcional | |||
}); | |||
} | |||
/** | |||
* Carrega imagem e aplica cache | |||
* @param {string} url - URL da imagem | |||
* @returns {Promise<string>} URL do blob (do cache ou recém-carregada) | |||
*/ | |||
function loadImage(url) { | |||
return get(url).then(function (cachedUrl) { | |||
if (cachedUrl) { | |||
return Promise.resolve(cachedUrl); | |||
} | |||
// Carrega a imagem e salva no cache | |||
return fetch(url, { mode: 'cors' }).then(function (response) { | |||
if (!response.ok) { | |||
throw new Error('Falha ao carregar imagem: ' + response.status); | |||
} | |||
return response.blob(); | |||
}).then(function (blob) { | |||
set(url, blob); | |||
return URL.createObjectURL(blob); | |||
}); | |||
}).catch(function () { | |||
// Em caso de erro, retorna a URL original | |||
return Promise.resolve(url); | |||
}); | |||
} | |||
return { | |||
loadImage: loadImage | |||
}; | |||
})(); | |||
/** | |||
* Applies background image to an element (com cache persistente) | |||
* @param {HTMLElement} el - The element to apply background to | |||
*/ | |||
function applyBg(el) { | function applyBg(el) { | ||
try { | try { | ||
var url = el.getAttribute('data-bg-url'); | |||
if (!url) { | if (!url) { | ||
var f = el.getAttribute('data-bg-file'); | |||
if (f) { | if (f) { | ||
url = buildBgURL(f); | url = buildBgURL(f); | ||
| Linha 29: | Linha 169: | ||
} | } | ||
} | } | ||
if (url) { | if (url) { | ||
el.style.backgroundImage = 'url("' + url + '")'; | // Tenta carregar do cache primeiro | ||
BgCache.loadImage(url).then(function (blobUrl) { | |||
el.style.backgroundImage = 'url("' + blobUrl + '")'; | |||
// Remove o atributo temporário se existir | |||
el.removeAttribute('data-bg-loading'); | |||
}).catch(function () { | |||
// Fallback para URL original em caso de erro | |||
el.style.backgroundImage = 'url("' + url + '")'; | |||
}); | |||
// Aplica URL original imediatamente enquanto carrega do cache (progressive enhancement) | |||
if (!el.hasAttribute('data-bg-loading')) { | |||
el.setAttribute('data-bg-loading', '1'); | |||
el.style.backgroundImage = 'url("' + url + '")'; | |||
} | |||
} | } | ||
} catch (e) { | } catch (e) { | ||
/ | /* no-op */ | ||
} | } | ||
} | } | ||
| Linha 41: | Linha 196: | ||
// Apply to future elements (AJAX) | // Apply to future elements (AJAX) | ||
new MutationObserver(function (mutations) { | |||
mutations.forEach(function (m) { | |||
if (m.type === 'childList') { | |||
m.addedNodes.forEach(function (n) { | |||
if (n.nodeType === 1) { | |||
if (n.hasAttribute && (n.hasAttribute('data-bg-file') || n.hasAttribute('data-bg-url'))) { | |||
applyBg(n); | |||
} | } | ||
}); | if (n.querySelectorAll) { | ||
n.querySelectorAll('[data-bg-file], [data-bg-url]').forEach(applyBg); | |||
} | |||
} | |||
} | }); | ||
} else if (m.type === 'attributes' && m.target) { | |||
applyBg(m.target); | |||
} | |||
}); | }); | ||
} | }).observe(document.body, { | ||
attributes: true, | |||
attributeFilter: ['data-bg-file', 'data-bg-url'], | |||
childList: true, | |||
subtree: true, | |||
}); | |||
})(); | })(); | ||
</script> | </script> | ||
Edição atual tal como às 15h09min de 2 de janeiro de 2026
<script>
/**
* @typedef {Object} MediaWiki
* @property {Object} util
* @property {Function} util.wikiScript
* @property {Function} util.wikiUrlencode
* @property {Object} config
* @property {Function} config.get
*/
// @ts-ignore - MediaWiki global
var mw = window.mw || {};
(function () {
/**
* Builds a MediaWiki file URL from a filename
* @param {string} fileName - The filename (with or without "Arquivo:" prefix)
* @returns {string} The full URL to the file
*/
function buildBgURL(fileName) {
if (!fileName) return ;
var base = (window.mw && mw.util && typeof mw.util.wikiScript === 'function')
? mw.util.wikiScript()
: (window.mw && mw.config ? (mw.config.get('wgScript') || '/index.php') : '/index.php');
var path = 'Especial:FilePath/' + fileName.replace(/^Arquivo:|^File:/, );
if (window.mw && mw.util && typeof mw.util.wikiUrlencode === 'function') {
return base + '?title=' + mw.util.wikiUrlencode(path);
} else {
return base + '?title=' + encodeURIComponent(path).replace(/%2F/g, '/');
}
}
/**
* Sistema de cache persistente usando IndexedDB
*/
var BgCache = (function () {
var DB_NAME = 'character-bg-cache';
var DB_VERSION = 1;
var STORE_NAME = 'backgrounds';
var db = null;
/**
* Inicializa o banco de dados IndexedDB
*/
function initDB() {
return new Promise(function (resolve, reject) {
if (db) {
resolve(db);
return;
}
if (!window.indexedDB) {
reject(new Error('IndexedDB não disponível'));
return;
}
var request = indexedDB.open(DB_NAME, DB_VERSION);
request.onerror = function () {
reject(request.error);
};
request.onsuccess = function () {
db = request.result;
resolve(db);
};
request.onupgradeneeded = function (event) {
var database = event.target.result;
if (!database.objectStoreNames.contains(STORE_NAME)) {
database.createObjectStore(STORE_NAME);
}
};
});
}
/**
* Obtém imagem do cache
* @param {string} url - URL da imagem
* @returns {Promise<string|null>} URL do blob ou null se não estiver em cache
*/
function get(url) {
return initDB().then(function (database) {
return new Promise(function (resolve, reject) {
var transaction = database.transaction([STORE_NAME], 'readonly');
var store = transaction.objectStore(STORE_NAME);
var request = store.get(url);
request.onsuccess = function () {
var blob = request.result;
if (blob && blob instanceof Blob) {
var blobUrl = URL.createObjectURL(blob);
resolve(blobUrl);
} else {
resolve(null);
}
};
request.onerror = function () {
reject(request.error);
};
});
}).catch(function () {
return Promise.resolve(null);
});
}
/**
* Salva imagem no cache
* @param {string} url - URL da imagem
* @param {Blob} blob - Blob da imagem
*/
function set(url, blob) {
initDB().then(function (database) {
var transaction = database.transaction([STORE_NAME], 'readwrite');
var store = transaction.objectStore(STORE_NAME);
store.put(blob, url);
}).catch(function () {
// Falha silenciosa - cache opcional
});
}
/**
* Carrega imagem e aplica cache
* @param {string} url - URL da imagem
* @returns {Promise<string>} URL do blob (do cache ou recém-carregada)
*/
function loadImage(url) {
return get(url).then(function (cachedUrl) {
if (cachedUrl) {
return Promise.resolve(cachedUrl);
}
// Carrega a imagem e salva no cache
return fetch(url, { mode: 'cors' }).then(function (response) {
if (!response.ok) {
throw new Error('Falha ao carregar imagem: ' + response.status);
}
return response.blob();
}).then(function (blob) {
set(url, blob);
return URL.createObjectURL(blob);
});
}).catch(function () {
// Em caso de erro, retorna a URL original
return Promise.resolve(url);
});
}
return {
loadImage: loadImage
};
})();
/**
* Applies background image to an element (com cache persistente)
* @param {HTMLElement} el - The element to apply background to
*/
function applyBg(el) {
try {
var url = el.getAttribute('data-bg-url');
if (!url) {
var f = el.getAttribute('data-bg-file');
if (f) {
url = buildBgURL(f);
el.setAttribute('data-bg-url', url);
}
}
if (url) {
// Tenta carregar do cache primeiro
BgCache.loadImage(url).then(function (blobUrl) {
el.style.backgroundImage = 'url("' + blobUrl + '")';
// Remove o atributo temporário se existir
el.removeAttribute('data-bg-loading');
}).catch(function () {
// Fallback para URL original em caso de erro
el.style.backgroundImage = 'url("' + url + '")';
});
// Aplica URL original imediatamente enquanto carrega do cache (progressive enhancement)
if (!el.hasAttribute('data-bg-loading')) {
el.setAttribute('data-bg-loading', '1');
el.style.backgroundImage = 'url("' + url + '")';
}
}
} catch (e) {
/* no-op */
}
}
// Aplicar backgrounds imediatamente
document.querySelectorAll('[data-bg-url], [data-bg-file]').forEach(applyBg);
// Apply to future elements (AJAX)
new MutationObserver(function (mutations) {
mutations.forEach(function (m) {
if (m.type === 'childList') {
m.addedNodes.forEach(function (n) {
if (n.nodeType === 1) {
if (n.hasAttribute && (n.hasAttribute('data-bg-file') || n.hasAttribute('data-bg-url'))) {
applyBg(n);
}
if (n.querySelectorAll) {
n.querySelectorAll('[data-bg-file], [data-bg-url]').forEach(applyBg);
}
}
});
} else if (m.type === 'attributes' && m.target) {
applyBg(m.target);
}
});
}).observe(document.body, {
attributes: true,
attributeFilter: ['data-bg-file', 'data-bg-url'],
childList: true,
subtree: true,
});
})();
</script>