This makes a better separation of actual content and meta data (readme, license, etc.) much better.
# Yet Another Firmware Selector
A simple OpenWrt firmware selector using autocompletion. Uses plain
-HTML/CSS/JavaScript. Checkout the [Demo](https://mwarning.github.io/yet_another_firmware_selector/).
+HTML/CSS/JavaScript. Checkout the [Demo](https://mwarning.github.io/yet-another-firmware-selector/www/).
![image](misc/screenshot.png)
## Run
-* Download repository and change directory
+* Checkput the repository and change to the project directory
* Start webserver (e.g. `python3 -m http.server`)
-* Go to `http://localhost:8000` in your web browser
+* Go to `http://localhost:8000/www/` in your web browser
-Configure with [config.js](config.js).
+Configure with [config.js](www/config.js).
## Attended Sysupgrade Support
+++ /dev/null
-var config = {
- // Default language, see i18n.js
- language: 'en',
- // Show help text for images
- showHelp: true,
- // Image overview file or path to the ASU API
- versions: {
- 'SNAPSHOT': 'misc/snapshot/overview.json',
- '19.07.1': 'misc/19.07.1/overview.json',
- '18.06.7': 'misc/18.06.7/overview.json'
- },
- // Build custom images
- // See https://github.com/aparcar/asu
- //asu_url: 'https://chef.libremesh.org'
-};
+++ /dev/null
-
-var translations = {
- 'ca': {
- 'tr-load': 'Descarregueu el microprogramari OpenWrt per al vostre dispositiu!',
- 'tr-title': 'Selector de microprogramari OpenWrt',
- 'tr-message': 'Feu servir el formulari de sota per seleccionar i descarregar el microprogramari per al vostre dispositiu!',
- 'tr-version-build': 'Compilació',
- 'tr-custom-build': 'Compilació personalitzada',
- 'tr-customize': 'Personalitzar',
- 'tr-request-build': 'Demanar la compilació',
- 'tr-model': 'Model:',
- 'tr-target': 'Plataforma:',
- 'tr-version': 'Versió:',
- 'tr-date': 'Data:',
- 'tr-downloads': 'Descàrregues',
- 'tr-custom-downloads': 'Descàrregues personalitzades',
- 'tr-factory-help': 'Les imatges Factory són per instal·lar OpenWrt als dispositius per primera vegada. Usualment, això es fa a través de la interfície web del microprogramari original.',
- 'tr-sysupgrade-help': 'Les imatges Sysupgrade són per instal·lar-les als dispositius que ja tenen OpenWrt. La imatge es pot instal·lar a través de la interfície web o del terminal.',
- 'tr-kernel-help': 'El nucli de Linux en una imatge separada.',
- 'tr-rootfs-help': 'El sistema de fitxers arrel en una imatge separada.',
- 'tr-sdcard-help': 'Una imatge feta per escriure-la a una targeta SD.',
- 'tr-tftp-help': 'Les imatges TFTP images es fan servir per instal·lar-les a un dispositiu mitjançant el mètode TFTP del carregador d\'arrencada.',
- 'tr-other-help': 'Un altre tipus d\'imatge.',
- 'tr-build-successful': 'La compilació ha tingut èxit',
- 'tr-build-failed': 'La compilació ha fallat',
- 'tr-request-image': 'Demanar la imatge',
- 'tr-check-again': 'Proveu de nou d\'aquí 5 segons...'
- },
- 'en': {
- 'tr-load': 'Download OpenWrt firmware for your device!',
- 'tr-title': 'OpenWrt Firmware Selector',
- 'tr-message': 'Please use the input below to download firmware for your device!',
- 'tr-version-build': 'Build',
- 'tr-custom-build': 'Custom Build',
- 'tr-customize': 'Customize',
- 'tr-request-build': 'Request Build',
- 'tr-model': 'Model:',
- 'tr-target': 'Platform:',
- 'tr-version': 'Version:',
- 'tr-date': 'Date:',
- 'tr-downloads': 'Downloads',
- 'tr-custom-downloads': 'Custom Downloads',
- 'tr-factory-help': 'Factory images are for flashing routers with OpenWrt for the first time. Usually via the web interface of the original firmware.',
- 'tr-sysupgrade-help': 'Sysupgrade images are for flashing routers that already run OpenWrt. The image can be applied using the web interface or the terminal.',
- 'tr-kernel-help': 'Linux kernel as a separate image.',
- 'tr-rootfs-help': 'Root file system as a separate image.',
- 'tr-sdcard-help': 'Image that is meant to be flashed onto a SD-Card.',
- 'tr-tftp-help': 'TFTP images are used to flash a device via the TFTP method of the bootloader.',
- 'tr-other-help': 'Other image type.',
- 'tr-build-successful': 'Build successful',
- 'tr-build-failed': 'Build failed',
- 'tr-request-image': 'Request image',
- 'tr-check-again': 'Check again in 5 seconds...'
- },
- 'es': {
- 'tr-load': 'Descargue el firmware OpenWrt para su dispositivo!',
- 'tr-title': 'Selector de firmware OpenWrt',
- 'tr-message': 'Utilice la entrada a continuación para descargar el firmware de su dispositivo!',
- 'tr-version-build': 'Compilar',
- 'tr-custom-build': 'Compilación personalizada',
- 'tr-customize': 'Personalizar',
- 'tr-request-build': 'Solicitar compilación',
- 'tr-model': 'Modelo:',
- 'tr-target': 'Plataforma:',
- 'tr-version': 'Versión:',
- 'tr-date': 'Fecha:',
- 'tr-downloads': 'Descargas',
- 'tr-custom-downloads': 'Descargas personalizadas',
- 'tr-factory-help': 'Las imágenes de fábrica son para enrutadores intermitentes con OpenWrt por primera vez. Generalmente a través de la interfaz web del firmware original.',
- 'tr-sysupgrade-help': 'Las imágenes de Sysupgrade son para enrutadores intermitentes que ya ejecutan OpenWrt. La imagen se puede aplicar utilizando la interfaz web o el terminal.',
- 'tr-kernel-help': 'Kernel de Linux como una imagen separada.',
- 'tr-rootfs-help': 'Sistema de archivos raíz como una imagen separada.',
- 'tr-sdcard-help': 'Imagen que debe ser mostrada en una tarjeta SD.',
- 'tr-tftp-help': 'Las imágenes TFTP se utilizan para flashear un dispositivo mediante el método TFTP del gestor de arranque.',
- 'tr-other-help': 'Otro tipo de imagen.',
- 'tr-build-successful': 'Compilación exitosa',
- 'tr-build-failed': 'Compilación fallida',
- 'tr-request-image': 'Solicitar imagen',
- 'tr-check-again': 'Verifique nuevamente en 5 segundos...'
- },
- 'no': {
- 'tr-load': 'Last ned OpenWrt fastvare for din enhet!',
- 'tr-title': 'OpenWrt fastvare utvelger',
- 'tr-message': 'Bruk feltene nedenfor for å laste ned fastvare til enheten din!',
- 'tr-version-build': 'Sammensetning',
- 'tr-custom-build': 'Tilpasset sammensetning',
- 'tr-customize': 'Tilpasse',
- 'tr-request-build': 'Be om sammensetning',
- 'tr-model': 'Modell:',
- 'tr-target': 'Platform:',
- 'tr-version': 'Versjon:',
- 'tr-date': 'Dato:',
- 'tr-downloads': 'Nedlastninger',
- 'tr-custom-downloads': 'Tilpassede nedlastninger',
- 'tr-factory-help': 'Factory avbildningen er for å laste rutere med OpenWrt første gang. Vanligvis via webgrensesnittet til den originale fastvaren.',
- 'tr-sysupgrade-help': 'Sysupgrade avbildningen er for rutere som allerede benytter OpenWrt. Avbildningen innstaleres gjennom webgrensesnittet eller terminalen.',
- 'tr-kernel-help': 'Linux kjernen som en egen avbildning.',
- 'tr-rootfs-help': 'Rotfilsystem som en egen avbildning.',
- 'tr-sdcard-help': 'Avbildning som er ment for et SD-kort.',
- 'tr-tftp-help': 'TFTP avbildninger er for å laste enheter via TFTP metoden i oppstartsprosedyren.',
- 'tr-other-help': 'Andre avbildningstyper.',
- 'tr-build-successful': 'Vellykket sammensetning',
- 'tr-build-failed': 'Sammensetningen feilet',
- 'tr-request-image': 'Be om avbildning',
- 'tr-check-again': 'Sjekk pånytt om 5 sekunder...'
- },
- 'de': {
- 'tr-load': 'Lade die OpenWrt Firmware für dein Gerät!',
- 'tr-title': 'OpenWrt Firmware Selector',
- 'tr-message': 'Bitte benutze die Eingabe um die passende Firmware zu finden!',
- 'tr-version-build': 'Release Build',
- 'tr-custom-build': 'Custom Build',
- 'tr-customize': 'Customize',
- 'tr-request-build': 'Request Build',
- 'tr-model': 'Model:',
- 'tr-target': 'Target',
- 'tr-version': 'Version:',
- 'tr-date': 'Datum:',
- 'tr-downloads': 'Downloads',
- 'tr-custom-downloads': 'Custom Downloads',
- 'tr-factory-help': 'Factory Abbilder werden über die Weboberfläche der originalen Firmware eingespielt.',
- 'tr-sysupgrade-help': 'Sysupgrade Abbilder werden für Geräte verwendet, die bereits OpenWrt laufen haben. Es ist möglich, existierende Einstellungen beizubehalten.',
- 'tr-kernel-help': 'Linux Kernel als separates Abbild.',
- 'tr-rootfs-help': 'Das Root Dateisystem als separates Abbild.',
- 'tr-sdcard-help': 'Image für SD Speicherkarten.',
- 'tr-tftp-help': 'TFTP Dateien können verwendet werden, um ein Gerät über die TFTP Method des Bootloader zu flashen.',
- 'tr-other-help': 'Sonstiger Imagetyp.',
- 'tr-build-successful': 'Build erfolgreich',
- 'tr-build-failed': 'Build fehlgeschlagen',
- 'tr-request-image': 'Frage nach image',
- 'tr-check-again': 'Nochmal nachfragen in 5 Sekunden...'
- },
- 'fr': {
- 'tr-load': 'Télécharger le firmware OpenWrt de votre périphérique !',
- 'tr-title': 'Sélecteur de Firmware',
- 'tr-message': 'Utiliser les entrées ci-dessous pour télécharger le firmware de votre périphérique !',
- 'tr-version-build': 'Build',
- 'tr-custom-build': 'Build Personnalisé',
- 'tr-customize': 'Personnalisation',
- 'tr-request-build': 'Requête de Build',
- 'tr-model': 'Modèle:',
- 'tr-target': 'Platform:',
- 'tr-version': 'Version:',
- 'tr-date': 'Date:',
- 'tr-downloads': 'Téléchargements',
- 'tr-custom-downloads': 'Téléchargements Personnalusés',
- 'tr-factory-help': 'Les images Factory sont prévues pour flasher les routers avec OpenWrt pour la première fois. Habituellement à partir de l\'interface web du firmware d\'origine.',
- 'tr-sysupgrade-help': 'Les images Sysupgrade sont prévues pour flasher les routers fonctionnant déjà avec OpenWrt. L\'image peut être installée à travers l\'interface web ou par le terminal.',
- 'tr-kernel-help': 'Linux kernel comme image séparée.',
- 'tr-rootfs-help': 'Root file system comme image séparée.',
- 'tr-sdcard-help': 'Image prévue pour être flashée sur une carte SD.',
- 'tr-tftp-help': 'TFTP images prévues pour flasher le périphérique via le démarrage par méthode TFTP.',
- 'tr-other-help': 'Autre type d\'image.',
- 'tr-build-successful': 'Succès du Build',
- 'tr-build-failed': 'Échec du Build',
- 'tr-request-image': 'Demade d\'image',
- 'tr-check-again': 'Essayer à nouveau dans 5 secondes...'
- },
- 'it': {
- 'tr-load': 'Scarica il firmware OpenWrt per il tuo dispositivo!',
- 'tr-title': 'OpenWrt Firmware Selector',
- 'tr-message': 'Usa la casella sottostante per scaricare il firmware per il tuo dispositivo!',
- 'tr-version-build': 'Build',
- 'tr-custom-build': 'Custom Build',
- 'tr-customize': 'Personalizza',
- 'tr-request-build': 'Richiedi Build',
- 'tr-model': 'Modell:',
- 'tr-target': 'Platform:',
- 'tr-version': 'Version:',
- 'tr-date': 'Data:',
- 'tr-downloads': 'Downloads',
- 'tr-custom-downloads': 'Download Personalizzati',
- 'tr-factory-help': 'Factory Image sono usate per installare OpenWrt su router per la prima volta. Di solito l\'immagine può essere applicata via l\'interfaccia web del firmware originale.',
- 'tr-sysupgrade-help': 'Sysupgrade Image sono usate per flashare router in cui OpenWrt è già installato. L\'immagine può essere applicata via interfaccia web o terminale.',
- 'tr-kernel-help': 'Linux kernel come immagine separata.',
- 'tr-rootfs-help': 'Root file system come immagine separata.',
- 'tr-sdcard-help': 'Immagine da flashare su scheda SD-Card separata.',
- 'tr-tftp-help': 'Immagini TFTP images sono usate per flashare un dispositivo con il metodo TFTP del bootloader.',
- 'tr-other-help': 'Other image type.',
- 'tr-build-successful': 'Build compilata con successo',
- 'tr-build-failed': 'Build fallita',
- 'tr-request-image': 'Richiedi immagine',
- 'tr-check-again': 'Prova di nuovo in 5 secondi...'
- },
- 'pl': {
- 'tr-load': 'Pobieranie oprogramowania OpenWrt!',
- 'tr-title': 'OpenWrt Firmware Selector',
- 'tr-message': 'Użyj pola poniżej żeby znaleźć obraz dla swojego urządzenia!',
- 'tr-version-build': 'Informacje o obrazie',
- 'tr-custom-build': 'Informacje o zmodyfikowanym obrazie',
- 'tr-customize': 'Modyfikacja',
- 'tr-request-build': 'Żądanie budowy obrazu',
- 'tr-model': 'Model:',
- 'tr-target': 'Platforma:',
- 'tr-version': 'Wersja:',
- 'tr-date': 'Data:',
- 'tr-downloads': 'Obrazy do pobrania',
- 'tr-custom-downloads': 'Zmodyfikowane obrazy do pobrania',
- 'tr-factory-help': 'Obraz factory używany jest do pierwszej instalacji OpenWrt. Zwykle można go użyć wykorzystując interfejs graficzny oryginalnego oprogramowania.',
- 'tr-sysupgrade-help': 'Obraz sysuprade używany jest do aktualizacji routerów z zainstalowanym już OpenWrt. Obraz można użyć przez GUI lub konsolę.',
- 'tr-kernel-help': 'Osobny obraz z kernelem linuksowym.',
- 'tr-rootfs-help': 'Osobny obraz z system plików.',
- 'tr-sdcard-help': 'Obraz do wgrania na kartę SD.',
- 'tr-tftp-help': 'Obraz TFTP służący do aktualizacji urządzenia z wykorzystaniem TFTP i bootloadera.',
- 'tr-other-help': 'Inny typ obrazu.',
- 'tr-build-successful': 'Budowanie zakończone pomyślnie',
- 'tr-build-failed': 'Błąd budowania',
- 'tr-request-image': 'Żądanie obrazu',
- 'tr-check-again': 'Sprawdź ponownie za 5 sekund...'
- },
- 'tr': {
- 'tr-load': 'Cihazınız için OpenWrt yazılımını indirin!',
- 'tr-title': 'OpenWrt Yazılım Seçicisi',
- 'tr-message': 'Cihazınız için yazılımı indirmek için lütfen aşağıdaki girişi kullanın!',
- 'tr-version-build': 'Sürüm',
- 'tr-custom-build': 'Özel Sürüm',
- 'tr-customize': 'Özelleştir',
- 'tr-request-build': 'Sürüm Oluştur',
- 'tr-model': 'Model:',
- 'tr-target': 'Platform:',
- 'tr-version': 'Versiyon:',
- 'tr-date': 'Tarih:',
- 'tr-downloads': 'İndirmeler',
- 'tr-custom-downloads': 'Özel İndirmeler',
- 'tr-factory-help': 'Fabrika imajları, ilk kez OpenWrt yüklenen cihazlar içindir. Genellikle orijinal ürün yazılımının web arayüzü üzerinden yüklenir.',
- 'tr-sysupgrade-help': 'Sysupgrade imajları, zaten OpenWrt kurulu cihazlar içindir. İmaj, web arayüzü veya terminal kullanılarak yüklenebilir.',
- 'tr-kernel-help': 'Linux kernel ayrı bir imaj olarak.',
- 'tr-rootfs-help': 'Kök Dosya Sistemi ayrı bir imaj olarak.',
- 'tr-sdcard-help': 'SD-Kart \'a kurulması planlanan imaj',
- 'tr-tftp-help': 'TFTP imajları, Bootloader \'ın TFTP yöntemi ile bir cihaza kurulması için kullanılır.',
- 'tr-other-help': 'Diğer imaj türü.',
- 'tr-build-successful': 'Oluşturma başarılı',
- 'tr-build-failed': 'Oluşturma başarısız',
- 'tr-request-image': 'Imaj oluştur',
- 'tr-check-again': '5 saniye icinde tekrar dene...'
- }
-};
-
-// Complement translations based on other translations
-//translations['en'] = Object.assign({}, translations['de'], translations['en']);
+++ /dev/null
-
-body {
- font-family: "Arial", sans-serif;
- margin: 0px;
-}
-
-#buildstatus a {
- color: inherit;
-}
-
-#models-autocomplete {
- width: 20em;
- display: inline-block;
-}
-
-.autocomplete {
- position: relative;
-}
-
-.autocomplete > input {
- border: 1px solid transparent;
- background-color: #f1f1f1;
- padding: 10px;
- width: 100%;
- border-radius: 4px;
-}
-
-.autocomplete-items {
- position: absolute;
- border: 1px solid #d4d4d4;
- border-bottom: none;
- border-top: none;
- z-index: 99;
- /*position the autocomplete items to be the same width as the container:*/
- top: 100%;
- left: 0;
- right: 0;
-}
-
-.autocomplete-items div {
- padding: 10px;
- cursor: pointer;
- background-color: #fff;
- border-bottom: 1px solid #d4d4d4;
-}
-
-/*when hovering an item:*/
-.autocomplete-items div:hover {
- background-color: #e9e9e9;
-}
-
-/*when navigating through the items using the arrow keys:*/
-.autocomplete-active {
- background-color: DodgerBlue !important;
- color: #ffffff;
-}
-
-header {
- font-weight: 500;
- width: 100%;
- z-index: 1100;
- box-shadow: 0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);
- background-color: #00A3E1;
-}
-
-h6 {
- margin: 0;
- font-size: 1.25rem;
- font-weight: 500;
- line-height: 1.6;
- letter-spacing: 0.0075em;
-}
-
-header > div {
- padding-left: 24px;
- padding-right: 24px;
- min-height: 64px;
-
- display: flex;
- position: relative;
- align-items: center;
- color: #fff;
-}
-
-.container {
- max-width: 1280px;
- padding-left: 32px;
- padding-right: 32px;
- width: 100%;
- box-sizing: border-box;
- margin-top: 30px;
- margin-right: auto;
- margin-left: auto;
- margin-bottom: 100px;
-}
-
-.container > div {
- padding: 10px 20px;
- text-align: left;
- box-shadow: 0px 1px 3px 0px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 2px 1px -1px rgba(0,0,0,0.12);
- border-radius: 4px;
- color: rgba(0, 0, 0, 0.87);
- transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
- background-color: #fff;
-}
-
-#versions {
- border: 1px solid transparent;
- background-color: #f1f1f1;
- padding: 10px;
- width: 10em;
- border-radius: 4px;
-}
-
-#language-selection {
- color: #fff;
- background-color: #1084b2;
- box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 3px 1px -2px
- rgba(0,0,0,0.12);
- padding: 6px 16px;
- border-radius: 4px;
- border: 0;
-
- /* hide arrow */
- -webkit-appearance: none;
- -moz-appearance: none;
- text-indent: 1px;
- text-overflow: '';
-}
-
-.download-link {
- text-decoration: none;
- border-radius: 4px;
- padding: 12px 16px;
- margin: 5px;
- font-size: 16px;
- cursor: pointer;
- letter-spacing: 0.05em;
- display: inline-flex;
- align-items: center;
- box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 3px 1px -2px rgba(0,0,0,0.12);
- color: #fff;
- background-color: #00A3E1;
-}
-
-.download-link:hover {
- background-color: #038fc6
-}
-
-.download-link :first-child {
- width: 30px;
- margin-right: 15px;
- margin-top: -2px;
- content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z' fill='%23fff'%3E%3C/path%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
-}
-
-#images .column {
- width: 5em;
- display: inline-block;
- line-height: 1.5;
-}
-
-#images {
- display: none;
-}
-
-#images > div {
- padding-top: 20px;
-}
-
-#image-model {
- font-weight: bold;
-}
-
-#custom {
- display: none;
-}
-
-#custom textarea {
- width: 500px;
- height: 120px;
- font-size: 16px;
- display: block;
-}
-
-#custom a :first-child {
- width: 30px;
- margin-right: 10px;
- margin-top: 0px;
- font-size: 36px;
-}
-
-#custom a {
- text-decoration: none;
- border-radius: 4px;
- padding: 2px 10px;
- margin: 5px;
- font-size: 16px;
- cursor: pointer;
- letter-spacing: 0.05em;
- display: inline-flex;
- align-items: center;
- box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 3px 1px -2px rgba(0,0,0,0.12);
- color: #fff;
- background-color: #00A3E1;
-}
-
-.download-help {
- display: none;
-}
-
-#buildspinner {
- float: left;
- height: 40px;
- padding-right: 12px;
- display: none;
-}
-
-#buildstatus {
- padding: 10px 0;
- display: none;
-}
-
-#footer {
- font-size: 0.8em;
- text-align: right;
-}
-
-#footer a {
- text-decoration: none;
-}
+++ /dev/null
-<!DOCTYPE html>
-
-<html lang="en">
-<head>
- <meta charset="utf-8"/>
- <title>OpenWrt Firmware Selector</title>
- <link rel="stylesheet" href="index.css" />
- <script src="i18n.js"></script>
- <script src="config.js"></script>
- <script src="index.js"></script>
-</head>
-<body onload="init()">
-
-<header>
- <div>
-<!--
- <h6 class="tr-title">OpenWrt Firmware Selector</h6>
--->
- <img src="logo.png" alt="Logo">
- <div style="flex-grow: 1;"></div>
-
- <select id="language-selection" size="1">
- <option value="ca">Català</option>
- <option value="en">English</option>
- <option value="es">Español</option>
- <option value="de">Deutsch</option>
- <option value="fr">Français</option>
- <option value="it">Italiano</option>
- <option value="no">Norsk</option>
- <option value="pl">Polski</option>
- <option value="tr">Türkçe</option>
- </select>
- </div>
-</header>
-
-<div class="container">
- <div>
- <h2 class="tr-load">Download OpenWrt firmware for your device!</h2>
- <p class="tr-message">Please use the input below to download firmware for your device!</p>
- <br>
-
- <select id="versions" size="1"></select>
- <div id="models-autocomplete" class="autocomplete">
- <input id="models" type="text" placeholder="Model" spellcheck="false" autocapitalize="off" autocorrect="off">
- </div>
-
- <br />
- <br />
-
- <div>
- <img id="buildspinner" src="spinner.gif" alt="Logo">
- <div id="buildstatus"></div>
- </div>
-
- <div id="images">
- <div id="custom">
- <h3 class="tr-customize">Customize</h3>
- <div class="autocomplete">
- <textarea id="packages" spellcheck="false" autocapitalize="off" autocorrect="off"></textarea>
- </div>
- <a href="javascript:build_asu_request()" class="custom-link">
- <span>⚙</span><span class="tr-request-build">Request Build</span>
- </a>
- </div>
-
- <div>
- <h3 id="images-title" class="tr-version-build">Release Build</h3>
- <div><span class="column tr-model">Model:</span> <span id="image-model"></span></div>
- <div><span class="column tr-target">Target:</span> <span id="image-target"></span></div>
- <div><span class="column tr-version">Version:</span> <span id="image-version"></span> (<span id="image-code"></span>)</div>
- <div><span class="column tr-date">Date:</span> <span id="image-date"></span></div>
- </div>
-
- <div id="download-links">
- <h3 id="downloads-title" class="tr-downloads">Downloads</h3>
- </div>
-
- <div>
- <span id="factory-help" class="download-help tr-factory-help">Factory images are for flashing routers with OpenWrt for the first time using the web interface of the original firmware.</span>
- <span id="sysupgrade-help" class="download-help tr-sysupgrade-help">Sysupgrade images are for flashing routers that already run OpenWrt. The image can be applied using the web interface or the console.</span>
- <span id="kernel-help" class="download-help tr-kernel-help">Linux kernel as a separate image.</span>
- <span id="rootfs-help" class="download-help tr-rootfs-help">Root file system as a separate image.</span>
- <span id="sdcard-help" class="download-help tr-sdcard-help">Image that is meant to be flashed on an SD-Card.</span>
- <span id="tftp-help" class="download-help tr-tftp-help">Image that can be applied using the TFTP meachnism of the bootloader</span>
- <span id="other-help" class="download-help tr-other-help">Image of unknown purpose.</span>
- </div>
- </div>
-
- <div id="footer">
- <span><a href="https://github.com/mwarning/yet_another_firmware_selector">YAFS</a> v2.2.1</span>
- </div>
- </div>
-</div>
-
-</body>
-</html>
+++ /dev/null
-
-var current_model = {};
-
-function $(id) {
- return document.getElementById(id);
-}
-
-function show(id) {
- $(id).style.display = 'block';
-}
-
-function hide(id) {
- $(id).style.display = 'none';
-}
-
-function split(str) {
- return str.match(/[^\s,]+/g) || [];
-}
-
-function get_model_titles(titles) {
- return titles.map(e => {
- if (e.title) {
- return e.title;
- } else {
- return ((e.vendor || '') + ' ' + (e.model || '') + ' ' + (e.variant || '')).trim();
- }
- }).join(' / ');
-}
-
-function build_asu_request() {
- if (!current_model || !current_model.id) {
- alert('bad profile');
- return;
- }
-
- function showStatus(message, url) {
- show('buildstatus');
- var tr = message.startsWith('tr-') ? message : '';
- if (url) {
- $('buildstatus').innerHTML = '<a href="' + url + '" class="' + tr + '">' + message + '</a>';
- } else {
- $('buildstatus').innerHTML = '<span class="' + tr + '"></span>';
- }
- translate();
- }
-
- // hide image view
- updateImages();
-
- show('buildspinner');
- showStatus('tr-request-image');
-
- var request_data = {
- 'target': current_model.target,
- 'profile': current_model.id,
- 'packages': split($('packages').value),
- 'version': $('versions').value
- }
-
- fetch(config.asu_url + '/api/build', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(request_data)
- })
- .then(response => {
- switch (response.status) {
- case 200:
- hide('buildspinner');
- showStatus('tr-build-successful');
-
- response.json()
- .then(mobj => {
- var download_url = config.asu_url + '/store/' + mobj.bin_dir;
- showStatus('tr-build-successful', download_url + '/buildlog.txt');
- updateImages(
- mobj.version_number,
- mobj.version_code,
- mobj.build_at,
- get_model_titles(mobj.titles),
- download_url, mobj, true
- );
- });
- break;
- case 202:
- showStatus('tr-check-again');
- setTimeout(_ => { build_asu_request() }, 5000);
- break;
- case 400: // bad request
- case 422: // bad package
- case 500: // build failed
- hide('buildspinner');
- response.json()
- .then(mobj => {
- var message = mobj['message'] || 'tr-build-failed';
- var url = mobj.buildlog ? (config.asu_url + '/store/' + mobj.bin_dir + '/buildlog.txt') : undefined;
- showStatus(message, url);
- })
- break;
- }
- })
- .catch(err => {
- hide('buildspinner');
- showStatus(err);
- })
-}
-
-function setupSelectList(select, items, onselection) {
- for (var i = 0; i < items.length; i += 1) {
- var option = document.createElement('OPTION');
- option.innerHTML = items[i];
- select.appendChild(option);
- }
-
- select.addEventListener('change', e => {
- onselection(items[select.selectedIndex]);
- });
-
- if (select.selectedIndex >= 0) {
- onselection(items[select.selectedIndex]);
- }
-}
-
-// Change the translation of the entire document
-function translate() {
- var mapping = translations[config.language];
- for (var tr in mapping) {
- Array.from(document.getElementsByClassName(tr))
- .forEach(e => { e.innerText = mapping[tr]; })
- }
-}
-
-function setupAutocompleteList(input, items, as_list, onbegin, onend) {
- var currentFocus = -1;
-
- // sort numbers and other characters separately
- var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
-
- items.sort(collator.compare);
-
- input.oninput = function(e) {
- onbegin();
-
- var offset = 0;
- var value = this.value;
- var value_list = [];
-
- if (as_list) {
- // automcomplete last text item
- offset = this.value.lastIndexOf(' ') + 1;
- value = this.value.substr(offset);
- value_list = split(this.value.substr(0, offset));
- }
-
- // close any already open lists of autocompleted values
- closeAllLists();
-
- if (!value) {
- return false;
- }
-
- // create a DIV element that will contain the items (values):
- var list = document.createElement('DIV');
- list.setAttribute('id', this.id + '-autocomplete-list');
- list.setAttribute('class', 'autocomplete-items');
- // append the DIV element as a child of the autocomplete container:
- this.parentNode.appendChild(list);
-
- var c = 0;
- for (var i = 0; i < items.length; i += 1) {
- var item = items[i];
-
- // match
- var j = item.toUpperCase().indexOf(value.toUpperCase());
- if (j < 0) {
- continue;
- }
-
- // do not offer a duplicate item
- if (as_list && value_list.indexOf(item) != -1) {
- continue;
- }
-
- c += 1;
- if (c >= 15) {
- var div = document.createElement('DIV');
- div.innerHTML = '...';
- list.appendChild(div);
- break;
- } else {
- var div = document.createElement('DIV');
- // make the matching letters bold:
- div.innerHTML = item.substr(0, j)
- + '<strong>' + item.substr(j, value.length) + '</strong>'
- + item.substr(j + value.length)
- + '<input type="hidden" value="' + item + '">';
-
- div.addEventListener('click', function(e) {
- // include selected value
- var selected = this.getElementsByTagName('input')[0].value;
- if (as_list) {
- input.value = value_list.join(' ') + ' ' + selected;
- } else {
- input.value = selected;
- }
- // close the list of autocompleted values,
- closeAllLists();
- onend(input);
- });
-
- list.appendChild(div);
- }
- }
- };
-
- input.onkeydown = function(e) {
- var x = document.getElementById(this.id + '-autocomplete-list');
- if (x) x = x.getElementsByTagName('div');
- if (e.keyCode == 40) {
- // key down
- currentFocus += 1;
- // and and make the current item more visible:
- setActive(x);
- } else if (e.keyCode == 38) {
- // key up
- currentFocus -= 1;
- // and and make the current item more visible:
- setActive(x);
- } else if (e.keyCode == 13) {
- // If the ENTER key is pressed, prevent the form from being submitted,
- e.preventDefault();
- if (currentFocus > -1) {
- // and simulate a click on the 'active' item:
- if (x) x[currentFocus].click();
- }
- }
- };
-
- input.onfocus = function() {
- onend(input);
- }
-
- // focus lost
- input.onblur = function() {
- onend(input);
- }
-
- function setActive(x) {
- // a function to classify an item as 'active':
- if (!x) return false;
- // start by removing the 'active' class on all items:
- for (var i = 0; i < x.length; i++) {
- x[i].classList.remove('autocomplete-active');
- }
- if (currentFocus >= x.length) currentFocus = 0;
- if (currentFocus < 0) currentFocus = (x.length - 1);
- // add class 'autocomplete-active':
- x[currentFocus].classList.add('autocomplete-active');
- }
-
- function closeAllLists(elmnt) {
- // close all autocomplete lists in the document,
- // except the one passed as an argument:
- var x = document.getElementsByClassName('autocomplete-items');
- for (var i = 0; i < x.length; i++) {
- if (elmnt != x[i] && elmnt != input) {
- x[i].parentNode.removeChild(x[i]);
- }
- }
- }
-
- // execute a function when someone clicks in the document:
- document.addEventListener('click', e => {
- closeAllLists(e.target);
- });
-}
-
-// for attended sysupgrade
-function updatePackageList(version, target) {
- // set available packages
- fetch(config.asu_url + '/' + config.versions[version] + '/' + target + '/index.json')
- .then(response => response.json())
- .then(all_packages => {
- setupAutocompleteList($('packages'), all_packages, true, _ => {}, textarea => {
- textarea.value = split(textarea.value)
- // make list unique, ignore minus
- .filter((value, index, self) => {
- var i = self.indexOf(value.replace(/^\-/, ''));
- return (i === index) || (i < 0);
- })
- // limit to available packages, ignore minus
- .filter((value, index) => all_packages.indexOf(value.replace(/^\-/, '')) !== -1)
- .join(' ');
- });
- });
-}
-
-function updateImages(version, code, date, model, url, mobj, is_custom) {
- // add download button for image
- function addLink(type, file) {
- var a = document.createElement('A');
- a.classList.add('download-link');
- a.href = url
- .replace('{target}', mobj.target)
- .replace('{version}', version)
- + '/' + file;
- var span = document.createElement('SPAN');
- span.appendChild(document.createTextNode(''));
- a.appendChild(span);
- a.appendChild(document.createTextNode(type.toUpperCase()));
-
- if (config.showHelp) {
- a.onmouseover = function() {
- // hide all help texts
- Array.from(document.getElementsByClassName('download-help'))
- .forEach(e => e.style.display = 'none');
- var lc = type.toLowerCase();
- if (lc.includes('sysupgrade')) {
- show('sysupgrade-help');
- } else if (lc.includes('factory') || lc == 'trx' || lc == 'chk') {
- show('factory-help');
- } else if (lc.includes('kernel') || lc.includes('zimage') || lc.includes('uimage')) {
- show('kernel-help');
- } else if (lc.includes('root')) {
- show('rootfs-help');
- } else if (lc.includes('sdcard')) {
- show('sdcard-help');
- } else if (lc.includes('tftp')) {
- show('tftp-help');
- } else {
- show('other-help');
- }
- };
- }
-
- $('download-links').appendChild(a);
- }
-
- function switchClass(id, from_class, to_class) {
- $(id).classList.remove(from_class);
- $(id).classList.add(to_class);
- }
-
- // remove all download links
- Array.from(document.getElementsByClassName('download-link'))
- .forEach(e => e.remove());
-
- // hide all help texts
- Array.from(document.getElementsByClassName('download-help'))
- .forEach(e => e.style.display = 'none');
-
- if (version && code && date && model && url && mobj) {
- var target = mobj.target;
- var images = mobj.images;
-
- // change between "version" and "custom" title
- if (is_custom) {
- switchClass('images-title', 'tr-version-build', 'tr-custom-build');
- switchClass('downloads-title', 'tr-version-downloads', 'tr-custom-downloads');
- } else {
- switchClass('images-title', 'tr-custom-build', 'tr-version-build');
- switchClass('downloads-title', 'tr-custom-downloads', 'tr-version-downloads');
- }
- // update title translation
- translate();
-
- // fill out build info
- $('image-model').innerText = model;
- $('image-target').innerText = target;
- $('image-version').innerText = version;
- $('image-code').innerText = code;
- $('image-date').innerText = date;
-
- images.sort((a, b) => a.name.localeCompare(b.name));
-
- for (var i in images) {
- addLink(images[i].type, images[i].name);
- }
-
- if (config.asu_url) {
- updatePackageList(version, target);
- }
-
- show('images');
- } else {
- hide('images');
- }
-}
-
-function init() {
- var build_date = "unknown"
- setupSelectList($('versions'), Object.keys(config.versions), version => {
- var url = config.versions[version];
- if (config.asu_url) {
- url = config.asu_url + '/' + url + '/profiles.json';
- }
- fetch(url)
- .then(obj => {
- build_date = obj.headers.get('last-modified');
- return obj.json();
- })
- .then(obj => {
- // handle native openwrt json format
- if ('profiles' in obj) {
- obj['models'] = {}
- for (const [key, value] of Object.entries(obj['profiles'])) {
- obj['models'][get_model_titles(value.titles)] = value
- obj['models'][get_model_titles(value.titles)]['id'] = key
- }
- }
- return obj
- })
- .then(obj => {
- setupAutocompleteList($('models'), Object.keys(obj['models']), false, updateImages, models => {
- var model = models.value;
- if (model in obj['models']) {
- var url = obj.url || 'unknown';
- var code = obj.version_code || 'unknown';
- var mobj = obj['models'][model];
- updateImages(version, code, build_date, model, url, mobj, false);
- current_model = mobj;
- } else {
- updateImages();
- current_model = {};
- }
- });
-
- // trigger model update when selected version changes
- $('models').onfocus();
- });
- });
-
- if (config.asu_url) {
- show('custom');
- }
-
- // hide fields
- updateImages();
-
- var user_lang = (navigator.language || navigator.userLanguage).split('-')[0];
- if (user_lang in translations) {
- config.language = user_lang;
- $('language-selection').value = user_lang;
- }
-
- translate();
-
- $('language-selection').onclick = function() {
- config.language = this.children[this.selectedIndex].value;
- translate();
- }
-}
--- /dev/null
+var config = {
+ // Default language, see i18n.js
+ language: 'en',
+ // Show help text for images
+ showHelp: true,
+ // Image overview file or path to the ASU API
+ versions: {
+ 'SNAPSHOT': '../misc/snapshot/overview.json',
+ '19.07.1': '../misc/19.07.1/overview.json',
+ '18.06.7': '../misc/18.06.7/overview.json'
+ },
+ // Build custom images
+ // See https://github.com/aparcar/asu
+ //asu_url: 'https://chef.libremesh.org'
+};
--- /dev/null
+
+var translations = {
+ 'ca': {
+ 'tr-load': 'Descarregueu el microprogramari OpenWrt per al vostre dispositiu!',
+ 'tr-title': 'Selector de microprogramari OpenWrt',
+ 'tr-message': 'Feu servir el formulari de sota per seleccionar i descarregar el microprogramari per al vostre dispositiu!',
+ 'tr-version-build': 'Compilació',
+ 'tr-custom-build': 'Compilació personalitzada',
+ 'tr-customize': 'Personalitzar',
+ 'tr-request-build': 'Demanar la compilació',
+ 'tr-model': 'Model:',
+ 'tr-target': 'Plataforma:',
+ 'tr-version': 'Versió:',
+ 'tr-date': 'Data:',
+ 'tr-downloads': 'Descàrregues',
+ 'tr-custom-downloads': 'Descàrregues personalitzades',
+ 'tr-factory-help': 'Les imatges Factory són per instal·lar OpenWrt als dispositius per primera vegada. Usualment, això es fa a través de la interfície web del microprogramari original.',
+ 'tr-sysupgrade-help': 'Les imatges Sysupgrade són per instal·lar-les als dispositius que ja tenen OpenWrt. La imatge es pot instal·lar a través de la interfície web o del terminal.',
+ 'tr-kernel-help': 'El nucli de Linux en una imatge separada.',
+ 'tr-rootfs-help': 'El sistema de fitxers arrel en una imatge separada.',
+ 'tr-sdcard-help': 'Una imatge feta per escriure-la a una targeta SD.',
+ 'tr-tftp-help': 'Les imatges TFTP images es fan servir per instal·lar-les a un dispositiu mitjançant el mètode TFTP del carregador d\'arrencada.',
+ 'tr-other-help': 'Un altre tipus d\'imatge.',
+ 'tr-build-successful': 'La compilació ha tingut èxit',
+ 'tr-build-failed': 'La compilació ha fallat',
+ 'tr-request-image': 'Demanar la imatge',
+ 'tr-check-again': 'Proveu de nou d\'aquí 5 segons...'
+ },
+ 'en': {
+ 'tr-load': 'Download OpenWrt firmware for your device!',
+ 'tr-title': 'OpenWrt Firmware Selector',
+ 'tr-message': 'Please use the input below to download firmware for your device!',
+ 'tr-version-build': 'Build',
+ 'tr-custom-build': 'Custom Build',
+ 'tr-customize': 'Customize',
+ 'tr-request-build': 'Request Build',
+ 'tr-model': 'Model:',
+ 'tr-target': 'Platform:',
+ 'tr-version': 'Version:',
+ 'tr-date': 'Date:',
+ 'tr-downloads': 'Downloads',
+ 'tr-custom-downloads': 'Custom Downloads',
+ 'tr-factory-help': 'Factory images are for flashing routers with OpenWrt for the first time. Usually via the web interface of the original firmware.',
+ 'tr-sysupgrade-help': 'Sysupgrade images are for flashing routers that already run OpenWrt. The image can be applied using the web interface or the terminal.',
+ 'tr-kernel-help': 'Linux kernel as a separate image.',
+ 'tr-rootfs-help': 'Root file system as a separate image.',
+ 'tr-sdcard-help': 'Image that is meant to be flashed onto a SD-Card.',
+ 'tr-tftp-help': 'TFTP images are used to flash a device via the TFTP method of the bootloader.',
+ 'tr-other-help': 'Other image type.',
+ 'tr-build-successful': 'Build successful',
+ 'tr-build-failed': 'Build failed',
+ 'tr-request-image': 'Request image',
+ 'tr-check-again': 'Check again in 5 seconds...'
+ },
+ 'es': {
+ 'tr-load': 'Descargue el firmware OpenWrt para su dispositivo!',
+ 'tr-title': 'Selector de firmware OpenWrt',
+ 'tr-message': 'Utilice la entrada a continuación para descargar el firmware de su dispositivo!',
+ 'tr-version-build': 'Compilar',
+ 'tr-custom-build': 'Compilación personalizada',
+ 'tr-customize': 'Personalizar',
+ 'tr-request-build': 'Solicitar compilación',
+ 'tr-model': 'Modelo:',
+ 'tr-target': 'Plataforma:',
+ 'tr-version': 'Versión:',
+ 'tr-date': 'Fecha:',
+ 'tr-downloads': 'Descargas',
+ 'tr-custom-downloads': 'Descargas personalizadas',
+ 'tr-factory-help': 'Las imágenes de fábrica son para enrutadores intermitentes con OpenWrt por primera vez. Generalmente a través de la interfaz web del firmware original.',
+ 'tr-sysupgrade-help': 'Las imágenes de Sysupgrade son para enrutadores intermitentes que ya ejecutan OpenWrt. La imagen se puede aplicar utilizando la interfaz web o el terminal.',
+ 'tr-kernel-help': 'Kernel de Linux como una imagen separada.',
+ 'tr-rootfs-help': 'Sistema de archivos raíz como una imagen separada.',
+ 'tr-sdcard-help': 'Imagen que debe ser mostrada en una tarjeta SD.',
+ 'tr-tftp-help': 'Las imágenes TFTP se utilizan para flashear un dispositivo mediante el método TFTP del gestor de arranque.',
+ 'tr-other-help': 'Otro tipo de imagen.',
+ 'tr-build-successful': 'Compilación exitosa',
+ 'tr-build-failed': 'Compilación fallida',
+ 'tr-request-image': 'Solicitar imagen',
+ 'tr-check-again': 'Verifique nuevamente en 5 segundos...'
+ },
+ 'no': {
+ 'tr-load': 'Last ned OpenWrt fastvare for din enhet!',
+ 'tr-title': 'OpenWrt fastvare utvelger',
+ 'tr-message': 'Bruk feltene nedenfor for å laste ned fastvare til enheten din!',
+ 'tr-version-build': 'Sammensetning',
+ 'tr-custom-build': 'Tilpasset sammensetning',
+ 'tr-customize': 'Tilpasse',
+ 'tr-request-build': 'Be om sammensetning',
+ 'tr-model': 'Modell:',
+ 'tr-target': 'Platform:',
+ 'tr-version': 'Versjon:',
+ 'tr-date': 'Dato:',
+ 'tr-downloads': 'Nedlastninger',
+ 'tr-custom-downloads': 'Tilpassede nedlastninger',
+ 'tr-factory-help': 'Factory avbildningen er for å laste rutere med OpenWrt første gang. Vanligvis via webgrensesnittet til den originale fastvaren.',
+ 'tr-sysupgrade-help': 'Sysupgrade avbildningen er for rutere som allerede benytter OpenWrt. Avbildningen innstaleres gjennom webgrensesnittet eller terminalen.',
+ 'tr-kernel-help': 'Linux kjernen som en egen avbildning.',
+ 'tr-rootfs-help': 'Rotfilsystem som en egen avbildning.',
+ 'tr-sdcard-help': 'Avbildning som er ment for et SD-kort.',
+ 'tr-tftp-help': 'TFTP avbildninger er for å laste enheter via TFTP metoden i oppstartsprosedyren.',
+ 'tr-other-help': 'Andre avbildningstyper.',
+ 'tr-build-successful': 'Vellykket sammensetning',
+ 'tr-build-failed': 'Sammensetningen feilet',
+ 'tr-request-image': 'Be om avbildning',
+ 'tr-check-again': 'Sjekk pånytt om 5 sekunder...'
+ },
+ 'de': {
+ 'tr-load': 'Lade die OpenWrt Firmware für dein Gerät!',
+ 'tr-title': 'OpenWrt Firmware Selector',
+ 'tr-message': 'Bitte benutze die Eingabe um die passende Firmware zu finden!',
+ 'tr-version-build': 'Release Build',
+ 'tr-custom-build': 'Custom Build',
+ 'tr-customize': 'Customize',
+ 'tr-request-build': 'Request Build',
+ 'tr-model': 'Model:',
+ 'tr-target': 'Target',
+ 'tr-version': 'Version:',
+ 'tr-date': 'Datum:',
+ 'tr-downloads': 'Downloads',
+ 'tr-custom-downloads': 'Custom Downloads',
+ 'tr-factory-help': 'Factory Abbilder werden über die Weboberfläche der originalen Firmware eingespielt.',
+ 'tr-sysupgrade-help': 'Sysupgrade Abbilder werden für Geräte verwendet, die bereits OpenWrt laufen haben. Es ist möglich, existierende Einstellungen beizubehalten.',
+ 'tr-kernel-help': 'Linux Kernel als separates Abbild.',
+ 'tr-rootfs-help': 'Das Root Dateisystem als separates Abbild.',
+ 'tr-sdcard-help': 'Image für SD Speicherkarten.',
+ 'tr-tftp-help': 'TFTP Dateien können verwendet werden, um ein Gerät über die TFTP Method des Bootloader zu flashen.',
+ 'tr-other-help': 'Sonstiger Imagetyp.',
+ 'tr-build-successful': 'Build erfolgreich',
+ 'tr-build-failed': 'Build fehlgeschlagen',
+ 'tr-request-image': 'Frage nach image',
+ 'tr-check-again': 'Nochmal nachfragen in 5 Sekunden...'
+ },
+ 'fr': {
+ 'tr-load': 'Télécharger le firmware OpenWrt de votre périphérique !',
+ 'tr-title': 'Sélecteur de Firmware',
+ 'tr-message': 'Utiliser les entrées ci-dessous pour télécharger le firmware de votre périphérique !',
+ 'tr-version-build': 'Build',
+ 'tr-custom-build': 'Build Personnalisé',
+ 'tr-customize': 'Personnalisation',
+ 'tr-request-build': 'Requête de Build',
+ 'tr-model': 'Modèle:',
+ 'tr-target': 'Platform:',
+ 'tr-version': 'Version:',
+ 'tr-date': 'Date:',
+ 'tr-downloads': 'Téléchargements',
+ 'tr-custom-downloads': 'Téléchargements Personnalusés',
+ 'tr-factory-help': 'Les images Factory sont prévues pour flasher les routers avec OpenWrt pour la première fois. Habituellement à partir de l\'interface web du firmware d\'origine.',
+ 'tr-sysupgrade-help': 'Les images Sysupgrade sont prévues pour flasher les routers fonctionnant déjà avec OpenWrt. L\'image peut être installée à travers l\'interface web ou par le terminal.',
+ 'tr-kernel-help': 'Linux kernel comme image séparée.',
+ 'tr-rootfs-help': 'Root file system comme image séparée.',
+ 'tr-sdcard-help': 'Image prévue pour être flashée sur une carte SD.',
+ 'tr-tftp-help': 'TFTP images prévues pour flasher le périphérique via le démarrage par méthode TFTP.',
+ 'tr-other-help': 'Autre type d\'image.',
+ 'tr-build-successful': 'Succès du Build',
+ 'tr-build-failed': 'Échec du Build',
+ 'tr-request-image': 'Demade d\'image',
+ 'tr-check-again': 'Essayer à nouveau dans 5 secondes...'
+ },
+ 'it': {
+ 'tr-load': 'Scarica il firmware OpenWrt per il tuo dispositivo!',
+ 'tr-title': 'OpenWrt Firmware Selector',
+ 'tr-message': 'Usa la casella sottostante per scaricare il firmware per il tuo dispositivo!',
+ 'tr-version-build': 'Build',
+ 'tr-custom-build': 'Custom Build',
+ 'tr-customize': 'Personalizza',
+ 'tr-request-build': 'Richiedi Build',
+ 'tr-model': 'Modell:',
+ 'tr-target': 'Platform:',
+ 'tr-version': 'Version:',
+ 'tr-date': 'Data:',
+ 'tr-downloads': 'Downloads',
+ 'tr-custom-downloads': 'Download Personalizzati',
+ 'tr-factory-help': 'Factory Image sono usate per installare OpenWrt su router per la prima volta. Di solito l\'immagine può essere applicata via l\'interfaccia web del firmware originale.',
+ 'tr-sysupgrade-help': 'Sysupgrade Image sono usate per flashare router in cui OpenWrt è già installato. L\'immagine può essere applicata via interfaccia web o terminale.',
+ 'tr-kernel-help': 'Linux kernel come immagine separata.',
+ 'tr-rootfs-help': 'Root file system come immagine separata.',
+ 'tr-sdcard-help': 'Immagine da flashare su scheda SD-Card separata.',
+ 'tr-tftp-help': 'Immagini TFTP images sono usate per flashare un dispositivo con il metodo TFTP del bootloader.',
+ 'tr-other-help': 'Other image type.',
+ 'tr-build-successful': 'Build compilata con successo',
+ 'tr-build-failed': 'Build fallita',
+ 'tr-request-image': 'Richiedi immagine',
+ 'tr-check-again': 'Prova di nuovo in 5 secondi...'
+ },
+ 'pl': {
+ 'tr-load': 'Pobieranie oprogramowania OpenWrt!',
+ 'tr-title': 'OpenWrt Firmware Selector',
+ 'tr-message': 'Użyj pola poniżej żeby znaleźć obraz dla swojego urządzenia!',
+ 'tr-version-build': 'Informacje o obrazie',
+ 'tr-custom-build': 'Informacje o zmodyfikowanym obrazie',
+ 'tr-customize': 'Modyfikacja',
+ 'tr-request-build': 'Żądanie budowy obrazu',
+ 'tr-model': 'Model:',
+ 'tr-target': 'Platforma:',
+ 'tr-version': 'Wersja:',
+ 'tr-date': 'Data:',
+ 'tr-downloads': 'Obrazy do pobrania',
+ 'tr-custom-downloads': 'Zmodyfikowane obrazy do pobrania',
+ 'tr-factory-help': 'Obraz factory używany jest do pierwszej instalacji OpenWrt. Zwykle można go użyć wykorzystując interfejs graficzny oryginalnego oprogramowania.',
+ 'tr-sysupgrade-help': 'Obraz sysuprade używany jest do aktualizacji routerów z zainstalowanym już OpenWrt. Obraz można użyć przez GUI lub konsolę.',
+ 'tr-kernel-help': 'Osobny obraz z kernelem linuksowym.',
+ 'tr-rootfs-help': 'Osobny obraz z system plików.',
+ 'tr-sdcard-help': 'Obraz do wgrania na kartę SD.',
+ 'tr-tftp-help': 'Obraz TFTP służący do aktualizacji urządzenia z wykorzystaniem TFTP i bootloadera.',
+ 'tr-other-help': 'Inny typ obrazu.',
+ 'tr-build-successful': 'Budowanie zakończone pomyślnie',
+ 'tr-build-failed': 'Błąd budowania',
+ 'tr-request-image': 'Żądanie obrazu',
+ 'tr-check-again': 'Sprawdź ponownie za 5 sekund...'
+ },
+ 'tr': {
+ 'tr-load': 'Cihazınız için OpenWrt yazılımını indirin!',
+ 'tr-title': 'OpenWrt Yazılım Seçicisi',
+ 'tr-message': 'Cihazınız için yazılımı indirmek için lütfen aşağıdaki girişi kullanın!',
+ 'tr-version-build': 'Sürüm',
+ 'tr-custom-build': 'Özel Sürüm',
+ 'tr-customize': 'Özelleştir',
+ 'tr-request-build': 'Sürüm Oluştur',
+ 'tr-model': 'Model:',
+ 'tr-target': 'Platform:',
+ 'tr-version': 'Versiyon:',
+ 'tr-date': 'Tarih:',
+ 'tr-downloads': 'İndirmeler',
+ 'tr-custom-downloads': 'Özel İndirmeler',
+ 'tr-factory-help': 'Fabrika imajları, ilk kez OpenWrt yüklenen cihazlar içindir. Genellikle orijinal ürün yazılımının web arayüzü üzerinden yüklenir.',
+ 'tr-sysupgrade-help': 'Sysupgrade imajları, zaten OpenWrt kurulu cihazlar içindir. İmaj, web arayüzü veya terminal kullanılarak yüklenebilir.',
+ 'tr-kernel-help': 'Linux kernel ayrı bir imaj olarak.',
+ 'tr-rootfs-help': 'Kök Dosya Sistemi ayrı bir imaj olarak.',
+ 'tr-sdcard-help': 'SD-Kart \'a kurulması planlanan imaj',
+ 'tr-tftp-help': 'TFTP imajları, Bootloader \'ın TFTP yöntemi ile bir cihaza kurulması için kullanılır.',
+ 'tr-other-help': 'Diğer imaj türü.',
+ 'tr-build-successful': 'Oluşturma başarılı',
+ 'tr-build-failed': 'Oluşturma başarısız',
+ 'tr-request-image': 'Imaj oluştur',
+ 'tr-check-again': '5 saniye icinde tekrar dene...'
+ }
+};
+
+// Complement translations based on other translations
+//translations['en'] = Object.assign({}, translations['de'], translations['en']);
--- /dev/null
+
+body {
+ font-family: "Arial", sans-serif;
+ margin: 0px;
+}
+
+#buildstatus a {
+ color: inherit;
+}
+
+#models-autocomplete {
+ width: 20em;
+ display: inline-block;
+}
+
+.autocomplete {
+ position: relative;
+}
+
+.autocomplete > input {
+ border: 1px solid transparent;
+ background-color: #f1f1f1;
+ padding: 10px;
+ width: 100%;
+ border-radius: 4px;
+}
+
+.autocomplete-items {
+ position: absolute;
+ border: 1px solid #d4d4d4;
+ border-bottom: none;
+ border-top: none;
+ z-index: 99;
+ /*position the autocomplete items to be the same width as the container:*/
+ top: 100%;
+ left: 0;
+ right: 0;
+}
+
+.autocomplete-items div {
+ padding: 10px;
+ cursor: pointer;
+ background-color: #fff;
+ border-bottom: 1px solid #d4d4d4;
+}
+
+/*when hovering an item:*/
+.autocomplete-items div:hover {
+ background-color: #e9e9e9;
+}
+
+/*when navigating through the items using the arrow keys:*/
+.autocomplete-active {
+ background-color: DodgerBlue !important;
+ color: #ffffff;
+}
+
+header {
+ font-weight: 500;
+ width: 100%;
+ z-index: 1100;
+ box-shadow: 0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);
+ background-color: #00A3E1;
+}
+
+h6 {
+ margin: 0;
+ font-size: 1.25rem;
+ font-weight: 500;
+ line-height: 1.6;
+ letter-spacing: 0.0075em;
+}
+
+header > div {
+ padding-left: 24px;
+ padding-right: 24px;
+ min-height: 64px;
+
+ display: flex;
+ position: relative;
+ align-items: center;
+ color: #fff;
+}
+
+.container {
+ max-width: 1280px;
+ padding-left: 32px;
+ padding-right: 32px;
+ width: 100%;
+ box-sizing: border-box;
+ margin-top: 30px;
+ margin-right: auto;
+ margin-left: auto;
+ margin-bottom: 100px;
+}
+
+.container > div {
+ padding: 10px 20px;
+ text-align: left;
+ box-shadow: 0px 1px 3px 0px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 2px 1px -1px rgba(0,0,0,0.12);
+ border-radius: 4px;
+ color: rgba(0, 0, 0, 0.87);
+ transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
+ background-color: #fff;
+}
+
+#versions {
+ border: 1px solid transparent;
+ background-color: #f1f1f1;
+ padding: 10px;
+ width: 10em;
+ border-radius: 4px;
+}
+
+#language-selection {
+ color: #fff;
+ background-color: #1084b2;
+ box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 3px 1px -2px
+ rgba(0,0,0,0.12);
+ padding: 6px 16px;
+ border-radius: 4px;
+ border: 0;
+
+ /* hide arrow */
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ text-indent: 1px;
+ text-overflow: '';
+}
+
+.download-link {
+ text-decoration: none;
+ border-radius: 4px;
+ padding: 12px 16px;
+ margin: 5px;
+ font-size: 16px;
+ cursor: pointer;
+ letter-spacing: 0.05em;
+ display: inline-flex;
+ align-items: center;
+ box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 3px 1px -2px rgba(0,0,0,0.12);
+ color: #fff;
+ background-color: #00A3E1;
+}
+
+.download-link:hover {
+ background-color: #038fc6
+}
+
+.download-link :first-child {
+ width: 30px;
+ margin-right: 15px;
+ margin-top: -2px;
+ content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z' fill='%23fff'%3E%3C/path%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
+}
+
+#images .column {
+ width: 5em;
+ display: inline-block;
+ line-height: 1.5;
+}
+
+#images {
+ display: none;
+}
+
+#images > div {
+ padding-top: 20px;
+}
+
+#image-model {
+ font-weight: bold;
+}
+
+#custom {
+ display: none;
+}
+
+#custom textarea {
+ width: 500px;
+ height: 120px;
+ font-size: 16px;
+ display: block;
+}
+
+#custom a :first-child {
+ width: 30px;
+ margin-right: 10px;
+ margin-top: 0px;
+ font-size: 36px;
+}
+
+#custom a {
+ text-decoration: none;
+ border-radius: 4px;
+ padding: 2px 10px;
+ margin: 5px;
+ font-size: 16px;
+ cursor: pointer;
+ letter-spacing: 0.05em;
+ display: inline-flex;
+ align-items: center;
+ box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 3px 1px -2px rgba(0,0,0,0.12);
+ color: #fff;
+ background-color: #00A3E1;
+}
+
+.download-help {
+ display: none;
+}
+
+#buildspinner {
+ float: left;
+ height: 40px;
+ padding-right: 12px;
+ display: none;
+}
+
+#buildstatus {
+ padding: 10px 0;
+ display: none;
+}
+
+#footer {
+ font-size: 0.8em;
+ text-align: right;
+}
+
+#footer a {
+ text-decoration: none;
+}
--- /dev/null
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+ <meta charset="utf-8"/>
+ <title>OpenWrt Firmware Selector</title>
+ <link rel="stylesheet" href="index.css" />
+ <script src="i18n.js"></script>
+ <script src="config.js"></script>
+ <script src="index.js"></script>
+</head>
+<body onload="init()">
+
+<header>
+ <div>
+<!--
+ <h6 class="tr-title">OpenWrt Firmware Selector</h6>
+-->
+ <img src="logo.png" alt="Logo">
+ <div style="flex-grow: 1;"></div>
+
+ <select id="language-selection" size="1">
+ <option value="ca">Català</option>
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ <option value="de">Deutsch</option>
+ <option value="fr">Français</option>
+ <option value="it">Italiano</option>
+ <option value="no">Norsk</option>
+ <option value="pl">Polski</option>
+ <option value="tr">Türkçe</option>
+ </select>
+ </div>
+</header>
+
+<div class="container">
+ <div>
+ <h2 class="tr-load">Download OpenWrt firmware for your device!</h2>
+ <p class="tr-message">Please use the input below to download firmware for your device!</p>
+ <br>
+
+ <select id="versions" size="1"></select>
+ <div id="models-autocomplete" class="autocomplete">
+ <input id="models" type="text" placeholder="Model" spellcheck="false" autocapitalize="off" autocorrect="off">
+ </div>
+
+ <br />
+ <br />
+
+ <div>
+ <img id="buildspinner" src="spinner.gif" alt="Logo">
+ <div id="buildstatus"></div>
+ </div>
+
+ <div id="images">
+ <div id="custom">
+ <h3 class="tr-customize">Customize</h3>
+ <div class="autocomplete">
+ <textarea id="packages" spellcheck="false" autocapitalize="off" autocorrect="off"></textarea>
+ </div>
+ <a href="javascript:build_asu_request()" class="custom-link">
+ <span>⚙</span><span class="tr-request-build">Request Build</span>
+ </a>
+ </div>
+
+ <div>
+ <h3 id="images-title" class="tr-version-build">Release Build</h3>
+ <div><span class="column tr-model">Model:</span> <span id="image-model"></span></div>
+ <div><span class="column tr-target">Target:</span> <span id="image-target"></span></div>
+ <div><span class="column tr-version">Version:</span> <span id="image-version"></span> (<span id="image-code"></span>)</div>
+ <div><span class="column tr-date">Date:</span> <span id="image-date"></span></div>
+ </div>
+
+ <div id="download-links">
+ <h3 id="downloads-title" class="tr-downloads">Downloads</h3>
+ </div>
+
+ <div>
+ <span id="factory-help" class="download-help tr-factory-help">Factory images are for flashing routers with OpenWrt for the first time using the web interface of the original firmware.</span>
+ <span id="sysupgrade-help" class="download-help tr-sysupgrade-help">Sysupgrade images are for flashing routers that already run OpenWrt. The image can be applied using the web interface or the console.</span>
+ <span id="kernel-help" class="download-help tr-kernel-help">Linux kernel as a separate image.</span>
+ <span id="rootfs-help" class="download-help tr-rootfs-help">Root file system as a separate image.</span>
+ <span id="sdcard-help" class="download-help tr-sdcard-help">Image that is meant to be flashed on an SD-Card.</span>
+ <span id="tftp-help" class="download-help tr-tftp-help">Image that can be applied using the TFTP meachnism of the bootloader</span>
+ <span id="other-help" class="download-help tr-other-help">Image of unknown purpose.</span>
+ </div>
+ </div>
+
+ <div id="footer">
+ <span><a href="https://github.com/mwarning/yet_another_firmware_selector">YAFS</a> v2.2.1</span>
+ </div>
+ </div>
+</div>
+
+</body>
+</html>
--- /dev/null
+
+var current_model = {};
+
+function $(id) {
+ return document.getElementById(id);
+}
+
+function show(id) {
+ $(id).style.display = 'block';
+}
+
+function hide(id) {
+ $(id).style.display = 'none';
+}
+
+function split(str) {
+ return str.match(/[^\s,]+/g) || [];
+}
+
+function get_model_titles(titles) {
+ return titles.map(e => {
+ if (e.title) {
+ return e.title;
+ } else {
+ return ((e.vendor || '') + ' ' + (e.model || '') + ' ' + (e.variant || '')).trim();
+ }
+ }).join(' / ');
+}
+
+function build_asu_request() {
+ if (!current_model || !current_model.id) {
+ alert('bad profile');
+ return;
+ }
+
+ function showStatus(message, url) {
+ show('buildstatus');
+ var tr = message.startsWith('tr-') ? message : '';
+ if (url) {
+ $('buildstatus').innerHTML = '<a href="' + url + '" class="' + tr + '">' + message + '</a>';
+ } else {
+ $('buildstatus').innerHTML = '<span class="' + tr + '"></span>';
+ }
+ translate();
+ }
+
+ // hide image view
+ updateImages();
+
+ show('buildspinner');
+ showStatus('tr-request-image');
+
+ var request_data = {
+ 'target': current_model.target,
+ 'profile': current_model.id,
+ 'packages': split($('packages').value),
+ 'version': $('versions').value
+ }
+
+ fetch(config.asu_url + '/api/build', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(request_data)
+ })
+ .then(response => {
+ switch (response.status) {
+ case 200:
+ hide('buildspinner');
+ showStatus('tr-build-successful');
+
+ response.json()
+ .then(mobj => {
+ var download_url = config.asu_url + '/store/' + mobj.bin_dir;
+ showStatus('tr-build-successful', download_url + '/buildlog.txt');
+ updateImages(
+ mobj.version_number,
+ mobj.version_code,
+ mobj.build_at,
+ get_model_titles(mobj.titles),
+ download_url, mobj, true
+ );
+ });
+ break;
+ case 202:
+ showStatus('tr-check-again');
+ setTimeout(_ => { build_asu_request() }, 5000);
+ break;
+ case 400: // bad request
+ case 422: // bad package
+ case 500: // build failed
+ hide('buildspinner');
+ response.json()
+ .then(mobj => {
+ var message = mobj['message'] || 'tr-build-failed';
+ var url = mobj.buildlog ? (config.asu_url + '/store/' + mobj.bin_dir + '/buildlog.txt') : undefined;
+ showStatus(message, url);
+ })
+ break;
+ }
+ })
+ .catch(err => {
+ hide('buildspinner');
+ showStatus(err);
+ })
+}
+
+function setupSelectList(select, items, onselection) {
+ for (var i = 0; i < items.length; i += 1) {
+ var option = document.createElement('OPTION');
+ option.innerHTML = items[i];
+ select.appendChild(option);
+ }
+
+ select.addEventListener('change', e => {
+ onselection(items[select.selectedIndex]);
+ });
+
+ if (select.selectedIndex >= 0) {
+ onselection(items[select.selectedIndex]);
+ }
+}
+
+// Change the translation of the entire document
+function translate() {
+ var mapping = translations[config.language];
+ for (var tr in mapping) {
+ Array.from(document.getElementsByClassName(tr))
+ .forEach(e => { e.innerText = mapping[tr]; })
+ }
+}
+
+function setupAutocompleteList(input, items, as_list, onbegin, onend) {
+ var currentFocus = -1;
+
+ // sort numbers and other characters separately
+ var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
+
+ items.sort(collator.compare);
+
+ input.oninput = function(e) {
+ onbegin();
+
+ var offset = 0;
+ var value = this.value;
+ var value_list = [];
+
+ if (as_list) {
+ // automcomplete last text item
+ offset = this.value.lastIndexOf(' ') + 1;
+ value = this.value.substr(offset);
+ value_list = split(this.value.substr(0, offset));
+ }
+
+ // close any already open lists of autocompleted values
+ closeAllLists();
+
+ if (!value) {
+ return false;
+ }
+
+ // create a DIV element that will contain the items (values):
+ var list = document.createElement('DIV');
+ list.setAttribute('id', this.id + '-autocomplete-list');
+ list.setAttribute('class', 'autocomplete-items');
+ // append the DIV element as a child of the autocomplete container:
+ this.parentNode.appendChild(list);
+
+ var c = 0;
+ for (var i = 0; i < items.length; i += 1) {
+ var item = items[i];
+
+ // match
+ var j = item.toUpperCase().indexOf(value.toUpperCase());
+ if (j < 0) {
+ continue;
+ }
+
+ // do not offer a duplicate item
+ if (as_list && value_list.indexOf(item) != -1) {
+ continue;
+ }
+
+ c += 1;
+ if (c >= 15) {
+ var div = document.createElement('DIV');
+ div.innerHTML = '...';
+ list.appendChild(div);
+ break;
+ } else {
+ var div = document.createElement('DIV');
+ // make the matching letters bold:
+ div.innerHTML = item.substr(0, j)
+ + '<strong>' + item.substr(j, value.length) + '</strong>'
+ + item.substr(j + value.length)
+ + '<input type="hidden" value="' + item + '">';
+
+ div.addEventListener('click', function(e) {
+ // include selected value
+ var selected = this.getElementsByTagName('input')[0].value;
+ if (as_list) {
+ input.value = value_list.join(' ') + ' ' + selected;
+ } else {
+ input.value = selected;
+ }
+ // close the list of autocompleted values,
+ closeAllLists();
+ onend(input);
+ });
+
+ list.appendChild(div);
+ }
+ }
+ };
+
+ input.onkeydown = function(e) {
+ var x = document.getElementById(this.id + '-autocomplete-list');
+ if (x) x = x.getElementsByTagName('div');
+ if (e.keyCode == 40) {
+ // key down
+ currentFocus += 1;
+ // and and make the current item more visible:
+ setActive(x);
+ } else if (e.keyCode == 38) {
+ // key up
+ currentFocus -= 1;
+ // and and make the current item more visible:
+ setActive(x);
+ } else if (e.keyCode == 13) {
+ // If the ENTER key is pressed, prevent the form from being submitted,
+ e.preventDefault();
+ if (currentFocus > -1) {
+ // and simulate a click on the 'active' item:
+ if (x) x[currentFocus].click();
+ }
+ }
+ };
+
+ input.onfocus = function() {
+ onend(input);
+ }
+
+ // focus lost
+ input.onblur = function() {
+ onend(input);
+ }
+
+ function setActive(x) {
+ // a function to classify an item as 'active':
+ if (!x) return false;
+ // start by removing the 'active' class on all items:
+ for (var i = 0; i < x.length; i++) {
+ x[i].classList.remove('autocomplete-active');
+ }
+ if (currentFocus >= x.length) currentFocus = 0;
+ if (currentFocus < 0) currentFocus = (x.length - 1);
+ // add class 'autocomplete-active':
+ x[currentFocus].classList.add('autocomplete-active');
+ }
+
+ function closeAllLists(elmnt) {
+ // close all autocomplete lists in the document,
+ // except the one passed as an argument:
+ var x = document.getElementsByClassName('autocomplete-items');
+ for (var i = 0; i < x.length; i++) {
+ if (elmnt != x[i] && elmnt != input) {
+ x[i].parentNode.removeChild(x[i]);
+ }
+ }
+ }
+
+ // execute a function when someone clicks in the document:
+ document.addEventListener('click', e => {
+ closeAllLists(e.target);
+ });
+}
+
+// for attended sysupgrade
+function updatePackageList(version, target) {
+ // set available packages
+ fetch(config.asu_url + '/' + config.versions[version] + '/' + target + '/index.json')
+ .then(response => response.json())
+ .then(all_packages => {
+ setupAutocompleteList($('packages'), all_packages, true, _ => {}, textarea => {
+ textarea.value = split(textarea.value)
+ // make list unique, ignore minus
+ .filter((value, index, self) => {
+ var i = self.indexOf(value.replace(/^\-/, ''));
+ return (i === index) || (i < 0);
+ })
+ // limit to available packages, ignore minus
+ .filter((value, index) => all_packages.indexOf(value.replace(/^\-/, '')) !== -1)
+ .join(' ');
+ });
+ });
+}
+
+function updateImages(version, code, date, model, url, mobj, is_custom) {
+ // add download button for image
+ function addLink(type, file) {
+ var a = document.createElement('A');
+ a.classList.add('download-link');
+ a.href = url
+ .replace('{target}', mobj.target)
+ .replace('{version}', version)
+ + '/' + file;
+ var span = document.createElement('SPAN');
+ span.appendChild(document.createTextNode(''));
+ a.appendChild(span);
+ a.appendChild(document.createTextNode(type.toUpperCase()));
+
+ if (config.showHelp) {
+ a.onmouseover = function() {
+ // hide all help texts
+ Array.from(document.getElementsByClassName('download-help'))
+ .forEach(e => e.style.display = 'none');
+ var lc = type.toLowerCase();
+ if (lc.includes('sysupgrade')) {
+ show('sysupgrade-help');
+ } else if (lc.includes('factory') || lc == 'trx' || lc == 'chk') {
+ show('factory-help');
+ } else if (lc.includes('kernel') || lc.includes('zimage') || lc.includes('uimage')) {
+ show('kernel-help');
+ } else if (lc.includes('root')) {
+ show('rootfs-help');
+ } else if (lc.includes('sdcard')) {
+ show('sdcard-help');
+ } else if (lc.includes('tftp')) {
+ show('tftp-help');
+ } else {
+ show('other-help');
+ }
+ };
+ }
+
+ $('download-links').appendChild(a);
+ }
+
+ function switchClass(id, from_class, to_class) {
+ $(id).classList.remove(from_class);
+ $(id).classList.add(to_class);
+ }
+
+ // remove all download links
+ Array.from(document.getElementsByClassName('download-link'))
+ .forEach(e => e.remove());
+
+ // hide all help texts
+ Array.from(document.getElementsByClassName('download-help'))
+ .forEach(e => e.style.display = 'none');
+
+ if (version && code && date && model && url && mobj) {
+ var target = mobj.target;
+ var images = mobj.images;
+
+ // change between "version" and "custom" title
+ if (is_custom) {
+ switchClass('images-title', 'tr-version-build', 'tr-custom-build');
+ switchClass('downloads-title', 'tr-version-downloads', 'tr-custom-downloads');
+ } else {
+ switchClass('images-title', 'tr-custom-build', 'tr-version-build');
+ switchClass('downloads-title', 'tr-custom-downloads', 'tr-version-downloads');
+ }
+ // update title translation
+ translate();
+
+ // fill out build info
+ $('image-model').innerText = model;
+ $('image-target').innerText = target;
+ $('image-version').innerText = version;
+ $('image-code').innerText = code;
+ $('image-date').innerText = date;
+
+ images.sort((a, b) => a.name.localeCompare(b.name));
+
+ for (var i in images) {
+ addLink(images[i].type, images[i].name);
+ }
+
+ if (config.asu_url) {
+ updatePackageList(version, target);
+ }
+
+ show('images');
+ } else {
+ hide('images');
+ }
+}
+
+function init() {
+ var build_date = "unknown"
+ setupSelectList($('versions'), Object.keys(config.versions), version => {
+ var url = config.versions[version];
+ if (config.asu_url) {
+ url = config.asu_url + '/' + url + '/profiles.json';
+ }
+ fetch(url)
+ .then(obj => {
+ build_date = obj.headers.get('last-modified');
+ return obj.json();
+ })
+ .then(obj => {
+ // handle native openwrt json format
+ if ('profiles' in obj) {
+ obj['models'] = {}
+ for (const [key, value] of Object.entries(obj['profiles'])) {
+ obj['models'][get_model_titles(value.titles)] = value
+ obj['models'][get_model_titles(value.titles)]['id'] = key
+ }
+ }
+ return obj
+ })
+ .then(obj => {
+ setupAutocompleteList($('models'), Object.keys(obj['models']), false, updateImages, models => {
+ var model = models.value;
+ if (model in obj['models']) {
+ var url = obj.url || 'unknown';
+ var code = obj.version_code || 'unknown';
+ var mobj = obj['models'][model];
+ updateImages(version, code, build_date, model, url, mobj, false);
+ current_model = mobj;
+ } else {
+ updateImages();
+ current_model = {};
+ }
+ });
+
+ // trigger model update when selected version changes
+ $('models').onfocus();
+ });
+ });
+
+ if (config.asu_url) {
+ show('custom');
+ }
+
+ // hide fields
+ updateImages();
+
+ var user_lang = (navigator.language || navigator.userLanguage).split('-')[0];
+ if (user_lang in translations) {
+ config.language = user_lang;
+ $('language-selection').value = user_lang;
+ }
+
+ translate();
+
+ $('language-selection').onclick = function() {
+ config.language = this.children[this.selectedIndex].value;
+ translate();
+ }
+}