@@ -4,8 +4,8 @@
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link rel="shortcut icon" type="image/x-icon" href="chrome://ca-archive/skin/logo.png">
|
||||
<link rel="stylesheet" href="chrome://ca-archive/skin/ca-archive.css">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="../skin/logo.png">
|
||||
<link rel="stylesheet" href="../skin/ca-archive.css">
|
||||
|
||||
<title>Classic Add-ons Archive</title>
|
||||
</head>
|
||||
@@ -16,58 +16,58 @@
|
||||
<div id="page" class="c">
|
||||
<div class="amo-header">
|
||||
<div class="header-search" role="search">
|
||||
<form id="search" action="caa:list">
|
||||
<form id="search" action="#list">
|
||||
<input id="search-q" name="q" autocomplete="off" title="" class="text placeholder" placeholder="search for add-ons" type="text">
|
||||
<button class="search-button" type="submit" title="Search" src="chrome://ca-archive/skin/btn-search.png"></button>
|
||||
<button class="search-button" type="submit" title="Search" src="../skin/btn-search.png"></button>
|
||||
</form>
|
||||
</div>
|
||||
<div id="masthead">
|
||||
<h1 class="site-title">
|
||||
<a href="caa:">
|
||||
<img alt="Firefox" src="chrome://ca-archive/skin/logo.png">Classic Add-ons Archive <font size="1">(2004-2018)</font></a>
|
||||
<a href="#">
|
||||
<img alt="Firefox" src="../skin/logo.png">Classic Add-ons Archive <font size="1">(2004-2018)</font></a>
|
||||
</h1>
|
||||
|
||||
<nav id="site-nav" class="menu-nav c">
|
||||
<ul>
|
||||
<li id="extensions">
|
||||
<a href="caa:list">Categories</a>
|
||||
<a href="#list">Categories</a>
|
||||
<ul class="two-col">
|
||||
<li><a href="caa:list/alerts-updates">Alerts & Updates</a></li>
|
||||
<li><a href="caa:list/appearance">Appearance</a></li>
|
||||
<li><a href="caa:list/bookmarks">Bookmarks</a></li>
|
||||
<li><a href="caa:list/download-management">Download Management</a></li>
|
||||
<li><a href="caa:list/feeds-news-blogging">Feeds, News & Blogging</a></li>
|
||||
<li><a href="caa:list/games-entertainment">Games & Entertainment</a></li>
|
||||
<li><a href="caa:list/language-support">Language Support</a></li>
|
||||
<li><a href="caa:list/photos-music-videos">Photos, Music & Videos</a></li>
|
||||
<li><a href="caa:list/privacy-security">Privacy & Security</a></li>
|
||||
<li><a href="caa:list/search-tools">Search Tools</a></li>
|
||||
<li><a href="caa:list/shopping">Shopping</a></li>
|
||||
<li><a href="caa:list/social-communication">Social & Communication</a></li>
|
||||
<li><a href="caa:list/tabs">Tabs</a></li>
|
||||
<li><a href="caa:list/web-development">Web Development</a></li>
|
||||
<li><a href="caa:list/other">Other</a></li>
|
||||
<li><a href="#list/alerts-updates">Alerts & Updates</a></li>
|
||||
<li><a href="#list/appearance">Appearance</a></li>
|
||||
<li><a href="#list/bookmarks">Bookmarks</a></li>
|
||||
<li><a href="#list/download-management">Download Management</a></li>
|
||||
<li><a href="#list/feeds-news-blogging">Feeds, News & Blogging</a></li>
|
||||
<li><a href="#list/games-entertainment">Games & Entertainment</a></li>
|
||||
<li><a href="#list/language-support">Language Support</a></li>
|
||||
<li><a href="#list/photos-music-videos">Photos, Music & Videos</a></li>
|
||||
<li><a href="#list/privacy-security">Privacy & Security</a></li>
|
||||
<li><a href="#list/search-tools">Search Tools</a></li>
|
||||
<li><a href="#list/shopping">Shopping</a></li>
|
||||
<li><a href="#list/social-communication">Social & Communication</a></li>
|
||||
<li><a href="#list/tabs">Tabs</a></li>
|
||||
<li><a href="#list/web-development">Web Development</a></li>
|
||||
<li><a href="#list/other">Other</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li id="listby">
|
||||
<a href="caa:list">List by</a>
|
||||
<a href="#list">List by</a>
|
||||
<ul>
|
||||
<li><a href="caa:list?sort=users">Most Users</a></li>
|
||||
<li><a href="caa:list?sort=rating">Top Rated</a></li>
|
||||
<li><a href="caa:list?sort=reviews">Most Reviews</a></li>
|
||||
<li><a href="caa:list?sort=created">Newest</a></li>
|
||||
<li><a href="caa:list?sort=updated">Recently Updated</a></li>
|
||||
<li><a href="caa:list?sort=name">Name </a></li>
|
||||
<li><a href="#list?sort=users">Most Users</a></li>
|
||||
<li><a href="#list?sort=rating">Top Rated</a></li>
|
||||
<li><a href="#list?sort=reviews">Most Reviews</a></li>
|
||||
<li><a href="#list?sort=created">Newest</a></li>
|
||||
<li><a href="#list?sort=updated">Recently Updated</a></li>
|
||||
<li><a href="#list?sort=name">Name </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li id="more">
|
||||
<a href="caa:">More…</a>
|
||||
<a href="#">More…</a>
|
||||
<ul>
|
||||
<li><a target="_blank" href="https://addons.mozilla.org/en-US/firefox/">Live Firefox Add-ons Site</a></li>
|
||||
<li><a target="_blank" href="http://web.archive.org/web/*/https://addons.mozilla.org/en-US/firefox/">Wayback Machine</a></li>
|
||||
<li><a href="caa:about">About</a></li>
|
||||
<li><a href="#about">About</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -83,7 +83,8 @@
|
||||
|
||||
</div>
|
||||
|
||||
<script src="chrome://ca-archive/content/ca-archive.js"></script>
|
||||
<script src="db-webext.js"></script>
|
||||
<script src="ca-archive.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,51 +1,107 @@
|
||||
"use strict";
|
||||
(function () {
|
||||
var Cu = Components.utils;
|
||||
|
||||
let dbname = "ca-archive-19030501.sqlite";
|
||||
// Compatibilidad con Chrome y Firefox
|
||||
const browserAPI = typeof browser !== "undefined" ? browser : chrome;
|
||||
|
||||
Cu.import("chrome://ca-archive/content/db.js");
|
||||
if (!DB.openDB(dbname, document)) {
|
||||
(async function () {
|
||||
const dbname = "ca-archive-19030501.sqlite";
|
||||
|
||||
// Cargar el módulo de base de datos
|
||||
// NOTA: Los scripts deben cargarse en el HTML antes de este script
|
||||
// o usar import dinámico
|
||||
|
||||
// Inicializar la base de datos (ahora es asíncrono)
|
||||
const dbOpened = await DB.openDB(dbname, document);
|
||||
if (!dbOpened) {
|
||||
console.error("Failed to open database");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
caa:addon/{slug|id}/versions[?page=[#ver]]
|
||||
caa:addon/{slug|id}/{eula|privacy|license/lid}
|
||||
caa:addon/{slug|id}
|
||||
caa:list[/category][?{tag|q}=][?sort=][?page=]
|
||||
caa:[search-query]
|
||||
*/
|
||||
/*
|
||||
Rutas soportadas (usando hash):
|
||||
#addon/{slug|id}/versions[?page=[#ver]]
|
||||
#addon/{slug|id}/{eula|privacy|license/lid}
|
||||
#addon/{slug|id}
|
||||
#list[/category][?{tag|q}=][?sort=][?page=]
|
||||
#about
|
||||
#{search-query}
|
||||
*/
|
||||
|
||||
try {
|
||||
let params, url = decodeURI(document.location);
|
||||
if ((params = /^caa:addon\/(.+?)\/versions\/?(\?page=(\d+)(#.+)?)?$/.exec(url)) !== null) {
|
||||
Cu.import("chrome://ca-archive/content/versions.js");
|
||||
Versions.showPage(document, DB.db, params[1], params[3]);
|
||||
} else if ((params = /^caa:addon\/(.+?)\/(eula|privacy|license\/(.+))$/.exec(url)) !== null) {
|
||||
Cu.import("chrome://ca-archive/content/epl.js");
|
||||
EPL.showPage(document, DB.db, params[1], params[2], params[3]);
|
||||
} else if ((params = /^caa:addon\/(.+?)\/?$/.exec(url)) !== null) {
|
||||
Cu.import("chrome://ca-archive/content/addon.js");
|
||||
Addon.showPage(document, DB.db, params[1]);
|
||||
} else if ((params = /^caa:list(\/([a-z-]+))?(\?tag=(.+?)|\?q=(.+?))?([\?|\&]sort=(\w+))?\&?(page=(\d+))?$/.exec(url)) !== null) {
|
||||
Cu.import("chrome://ca-archive/content/list.js");
|
||||
List.showPage(document, DB.db, params[2], params[4], params[5], params[7], params[9]);
|
||||
} else if (url == "caa:") {
|
||||
Cu.import("chrome://ca-archive/content/tcloud.js");
|
||||
TCloud.showPage(document, DB.db);
|
||||
} else if (url == "caa:about") {
|
||||
Cu.import("chrome://ca-archive/content/about.js");
|
||||
About.showPage(document, DB.db);
|
||||
} else if ((params = /^caa:(.+)$/.exec(url)) !== null) {
|
||||
Cu.import("chrome://ca-archive/content/list.js");
|
||||
List.showPage(document, DB.db, undefined, undefined, params[1], undefined, undefined);
|
||||
} else {
|
||||
document.location = "caa:list";
|
||||
// Función para manejar la navegación
|
||||
async function handleNavigation() {
|
||||
try {
|
||||
// Obtener la URL del hash
|
||||
let hash = window.location.hash.substring(1); // Remover el '#'
|
||||
if (!hash) {
|
||||
hash = "list"; // Por defecto mostrar listado
|
||||
}
|
||||
|
||||
let params;
|
||||
const url = decodeURI(hash);
|
||||
|
||||
if ((params = /^addon\/(.+?)\/versions\/?(\?page=(\d+)(#.+)?)?$/.exec(url)) !== null) {
|
||||
// Cargar dinámicamente el módulo de versiones si no está cargado
|
||||
if (typeof Versions === "undefined") {
|
||||
await loadScript("versions.js");
|
||||
}
|
||||
Versions.showPage(document, DB.db, params[1], params[3]);
|
||||
} else if ((params = /^addon\/(.+?)\/(eula|privacy|license\/(.+))$/.exec(url)) !== null) {
|
||||
if (typeof EPL === "undefined") {
|
||||
await loadScript("epl.js");
|
||||
}
|
||||
EPL.showPage(document, DB.db, params[1], params[2], params[3]);
|
||||
} else if ((params = /^addon\/(.+?)\/?$/.exec(url)) !== null) {
|
||||
if (typeof Addon === "undefined") {
|
||||
await loadScript("addon.js");
|
||||
}
|
||||
Addon.showPage(document, DB.db, params[1]);
|
||||
} else if ((params = /^list(\/([a-z-]+))?(\?tag=(.+?)|\?q=(.+?))?([\?|\&]sort=(\w+))?\&?(page=(\d+))?$/.exec(url)) !== null) {
|
||||
if (typeof List === "undefined") {
|
||||
await loadScript("list.js");
|
||||
}
|
||||
List.showPage(document, DB.db, params[2], params[4], params[5], params[7], params[9]);
|
||||
} else if (url === "" || url === "list") {
|
||||
if (typeof TCloud === "undefined") {
|
||||
await loadScript("tcloud.js");
|
||||
}
|
||||
TCloud.showPage(document, DB.db);
|
||||
} else if (url === "about") {
|
||||
if (typeof About === "undefined") {
|
||||
await loadScript("about.js");
|
||||
}
|
||||
About.showPage(document, DB.db);
|
||||
} else {
|
||||
// Búsqueda genérica
|
||||
if (typeof List === "undefined") {
|
||||
await loadScript("list.js");
|
||||
}
|
||||
List.showPage(document, DB.db, undefined, undefined, url, undefined, undefined);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Navigation error:", e);
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
DB.closeDB();
|
||||
|
||||
// Función auxiliar para cargar scripts dinámicamente
|
||||
function loadScript(filename) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement("script");
|
||||
script.src = filename;
|
||||
script.onload = () => resolve();
|
||||
script.onerror = () => reject(new Error(`Failed to load script: ${filename}`));
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
// Manejar el cambio de hash
|
||||
window.addEventListener("hashchange", handleNavigation);
|
||||
|
||||
// Inicializar la navegación inicial
|
||||
await handleNavigation();
|
||||
|
||||
// Cerrar la base de datos cuando se cierre la página
|
||||
window.addEventListener("beforeunload", () => {
|
||||
DB.closeDB();
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
245
content/db-webext.js
Archivo normal
245
content/db-webext.js
Archivo normal
@@ -0,0 +1,245 @@
|
||||
"use strict";
|
||||
|
||||
// Módulo de base de datos para WebExtensions
|
||||
// Usa sql.js (SQLite compilado a JavaScript/WebAssembly)
|
||||
|
||||
const DB = {
|
||||
db: null,
|
||||
SQL: null,
|
||||
|
||||
/**
|
||||
* Inicializa sql.js (debe ser llamado primero)
|
||||
*/
|
||||
async initSQL() {
|
||||
if (this.SQL) return this.SQL;
|
||||
|
||||
// Cargar sql.js desde CDN o localmente
|
||||
// Para producción, incluir sql.js localmente
|
||||
try {
|
||||
// Intentar cargar sql.js si no está ya cargado
|
||||
if (typeof window.initSqlJs === "undefined") {
|
||||
await this.loadScript("https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.8.0/sql-wasm.js");
|
||||
}
|
||||
|
||||
this.SQL = await initSqlJs({
|
||||
locateFile: file => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.8.0/${file}`
|
||||
});
|
||||
|
||||
return this.SQL;
|
||||
} catch (e) {
|
||||
console.error("Failed to initialize sql.js:", e);
|
||||
throw new Error("Could not load SQL engine");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Cargar script dinámicamente
|
||||
*/
|
||||
loadScript(src) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement("script");
|
||||
script.src = src;
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Abre o crea la base de datos
|
||||
* @param {string} dbname - Nombre del archivo de base de datos
|
||||
* @param {Document} document - Documento HTML
|
||||
* @returns {boolean} - true si se abrió correctamente
|
||||
*/
|
||||
async openDB(dbname, document) {
|
||||
try {
|
||||
await this.initSQL();
|
||||
|
||||
// Intentar cargar la base de datos desde el storage de la extensión
|
||||
const dbData = await this.loadDBFromStorage(dbname);
|
||||
|
||||
if (dbData) {
|
||||
// Cargar base de datos existente
|
||||
this.db = new this.SQL.Database(new Uint8Array(dbData));
|
||||
console.log("Database loaded from storage");
|
||||
} else {
|
||||
// Intentar descargar la base de datos empaquetada
|
||||
await this.downloadAndStoreDB(dbname, document);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error("Error opening database:", e);
|
||||
this.showMessage(document,
|
||||
"Error loading database. Please check the console for details.",
|
||||
"db-warning"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Carga la base de datos desde el storage local de la extensión
|
||||
*/
|
||||
async loadDBFromStorage(dbname) {
|
||||
try {
|
||||
const browserAPI = typeof browser !== "undefined" ? browser : chrome;
|
||||
const result = await browserAPI.storage.local.get(dbname);
|
||||
return result[dbname];
|
||||
} catch (e) {
|
||||
console.warn("Could not load DB from storage:", e);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Descarga y almacena la base de datos
|
||||
*/
|
||||
async downloadAndStoreDB(dbname, document) {
|
||||
this.showMessage(document,
|
||||
"Loading database for the first time. Please wait...",
|
||||
"db-warning ok"
|
||||
);
|
||||
|
||||
try {
|
||||
// Intentar cargar desde la extensión
|
||||
const browserAPI = typeof browser !== "undefined" ? browser : chrome;
|
||||
const dbUrl = browserAPI.runtime.getURL(`content/db/${dbname}`);
|
||||
|
||||
const response = await fetch(dbUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch database: ${response.status}`);
|
||||
}
|
||||
|
||||
const arrayBuffer = await response.arrayBuffer();
|
||||
this.db = new this.SQL.Database(new Uint8Array(arrayBuffer));
|
||||
|
||||
// Guardar en storage para uso futuro
|
||||
await this.saveDBToStorage(dbname, arrayBuffer);
|
||||
|
||||
this.showMessage(document,
|
||||
"Database loaded successfully!",
|
||||
"db-warning ok"
|
||||
);
|
||||
|
||||
console.log("Database downloaded and stored");
|
||||
} catch (e) {
|
||||
console.error("Error downloading database:", e);
|
||||
this.showMessage(document,
|
||||
"Failed to load database. Please reinstall the extension.",
|
||||
"db-warning bad"
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Guarda la base de datos en el storage local
|
||||
*/
|
||||
async saveDBToStorage(dbname, arrayBuffer) {
|
||||
try {
|
||||
const browserAPI = typeof browser !== "undefined" ? browser : chrome;
|
||||
|
||||
// Convertir ArrayBuffer a Array para storage
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
const array = Array.from(uint8Array);
|
||||
|
||||
// Chrome tiene límite de storage, considerar usar chunks para DBs grandes
|
||||
// Por ahora, intentar guardar directamente
|
||||
await browserAPI.storage.local.set({ [dbname]: array });
|
||||
|
||||
console.log("Database saved to storage");
|
||||
} catch (e) {
|
||||
console.warn("Could not save DB to storage (may be too large):", e);
|
||||
// No es crítico si falla, se recargará la próxima vez
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Muestra un mensaje en la página
|
||||
*/
|
||||
showMessage(document, msg, style) {
|
||||
const div = document.createElement("div");
|
||||
div.className = style;
|
||||
div.appendChild(document.createTextNode(msg));
|
||||
const page = document.getElementById("page");
|
||||
if (page) {
|
||||
page.appendChild(div);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Cierra la base de datos
|
||||
*/
|
||||
closeDB() {
|
||||
if (this.db) {
|
||||
this.db.close();
|
||||
this.db = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Ejecuta una consulta SQL
|
||||
*/
|
||||
execute(sql, params = []) {
|
||||
if (!this.db) {
|
||||
throw new Error("Database not opened");
|
||||
}
|
||||
return this.db.exec(sql, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Ejecuta una consulta y retorna la primera fila
|
||||
*/
|
||||
executeRow(sql, params = []) {
|
||||
const results = this.execute(sql, params);
|
||||
if (results.length > 0 && results[0].values.length > 0) {
|
||||
return results[0].values[0];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepara una statement (compatible con API antigua)
|
||||
*/
|
||||
createStatement(sql) {
|
||||
if (!this.db) {
|
||||
throw new Error("Database not opened");
|
||||
}
|
||||
|
||||
// Crear un objeto que emule la API de mozIStorageStatement
|
||||
const stmt = this.db.prepare(sql);
|
||||
|
||||
return {
|
||||
params: {},
|
||||
executeStep() {
|
||||
return stmt.step();
|
||||
},
|
||||
reset() {
|
||||
stmt.reset();
|
||||
},
|
||||
finalize() {
|
||||
stmt.free();
|
||||
},
|
||||
row: new Proxy({}, {
|
||||
get(target, prop) {
|
||||
return stmt.get()[stmt.getColumnNames().indexOf(prop)];
|
||||
}
|
||||
}),
|
||||
getString(index) {
|
||||
return stmt.get()[index];
|
||||
},
|
||||
getInt32(index) {
|
||||
return stmt.get()[index];
|
||||
},
|
||||
getDouble(index) {
|
||||
return stmt.get()[index];
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Hacer disponible globalmente para compatibilidad
|
||||
if (typeof window !== "undefined") {
|
||||
window.DB = DB;
|
||||
}
|
||||
Referencia en una nueva incidencia
Block a user