Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Dana Meli 2018-11-03 11:42:30 -07:00
commit 89b6c27b4e
52 changed files with 11240 additions and 277 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@ -4,7 +4,9 @@
2. [How to report issues](#how-to-report-issues)
3. [Adding translations](#adding-translations)
4. [Pull requests](#pull-requests)
5. [Contact us](#contact-us)
5. [Scripts](#scripts)
6. [Updating locale files](#updating-locale-files-admin-only)
7. [Contact us](#contact-us)
## Getting involved
@ -32,6 +34,26 @@ You can help us translate the extension on [Transifex](https://www.transifex.com
* Make any changes within a branch of this repository (not the `master` branch).
* Submit a pull request and include a reference to the initial issue with the discussion.
## Scripts
* `npm run lint` - Run ESLint on all JavaScript files.
* `npm run update` - Runs update-node & update-main scripts.
* `npm run update-quick` - Updates development dependencies (uses `npm update`; does not include new dependencies).
* `npm run update-locales` (admin only)- Updates locale files from Transifex. See the [updating locale files section](#updating-locale-files-admin-only) for more details.
* `npm run update-main` - Runs update-versions & update-codemirror.
* `npm run update-node` - Update development dependencies, removes & reinstalls `node_modules` folder (slow).
* `npm run update-transifex` (admin only) - Upload `en/messages.json` source to Transifex.
* `npm run update-vendor` - Update codemirror, codemirror themes & other vendor libraries.
* `npm run update-versions` - Update version of `manifest.json` to match `package.json`.
* `npm run zip` - Run update-versions, then compress required files into a zip file.
## Updating locale files (admin only)
* Make sure you have the Transifex client installed. Follow the instructions on [this page](https://docs.transifex.com/client/installing-the-client).
* Contact another admin if you need the `.transifexrc` file in the root folder. It includes the API key to use Transifex's API.
* Use `npm run update-locales` in the command line to [update the language files](https://docs.transifex.com/client/pull) in the repo.
* Use `npm run update-transifex` in the command line to [upload the source](https://docs.transifex.com/client/push) `en/messages.json` file to Transifex.
## Contact us
If you prefer a more informal method of getting in touch or starting a conversation, please [join us on Discord](https://discordapp.com/widget?id=379521691774353408) or leave a comment in the [discussion section](https://add0n.com/stylus.html#reviews). We will monitor any discussions there and join in, and it may be a more appropriate venue for opinions and less urgent suggestions.

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ package-lock.json
yarn.lock
*.zip
.eslintcache
.transifexrc

10
.tx/config Normal file
View File

@ -0,0 +1,10 @@
[main]
host = https://www.transifex.com
[Stylus.messages]
file_filter = _locales/<lang>/messages.json
minimum_perc = 0
source_file = _locales/en/messages.json
source_lang = en_US
type = CHROME

View File

@ -160,4 +160,4 @@
"updateCompleted": {
"message": "اكتمل التحديث."
}
}
}

View File

@ -575,4 +575,4 @@
"writeStyleForURL": {
"message": "този адрес"
}
}
}

View File

@ -284,4 +284,4 @@
"manageOnlyUsercss": {
"message": "Само Потребителскиcss стилове"
}
}
}

View File

@ -258,11 +258,11 @@
"filteredStyles": {
"message": "zobrazeno $numShown$ z $numTotal$",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -742,6 +742,9 @@
"styleBeautifyIndentConditional": {
"message": "Odsadit @media, @supports"
},
"styleBeautifyPreserveNewlines": {
"message": "Zachovat nové řádky"
},
"styleCancelEditLabel": {
"message": "Zpět ke správě"
},
@ -776,14 +779,14 @@
"styleInstallOverwrite": {
"message": "Styl „$stylename$“ je již nainstalován. Přepsat?\nVerze: $oldVersion$ → $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -798,6 +801,14 @@
}
}
},
"styleMetaErrorRangeOrNumber": {
"message": "Neplatná @var $type$: hodnota musí být pole obsahující alespoň jedno číslo na nulové pozici",
"placeholders": {
"type": {
"content": "$1"
}
}
},
"styleMetaErrorPreprocessor": {
"message": "Nepodporovaný @preprocessor: $preprocessor$",
"placeholders": {
@ -953,6 +964,9 @@
"updatesCurrentlyInstalled": {
"message": "Instalované aktualizace:"
},
"usercssAvoidOverwriting": {
"message": "Prosím, změňte hodnotu @name nebo @namespace ať nedojde k přepsání existujícího stylu."
},
"usercssConfigIncomplete": {
"message": "Styl byl aktualizován nebo smazán po zobrazení dialogu konfigurace. Tyto proměnné nebyly uloženy aby se předešlo poškození metadat stylu."
},
@ -977,4 +991,4 @@
"writeStyleForURL": {
"message": "tuto URL"
}
}
}

View File

@ -246,11 +246,11 @@
"filteredStyles": {
"message": "$numShown$ von $numTotal$ gesamt",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -776,14 +776,14 @@
"styleInstallOverwrite": {
"message": "\"$stylename$\" ist bereits installiert. Überschreiben?\nVersion: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -798,6 +798,14 @@
}
}
},
"styleMetaErrorRangeOrNumber": {
"message": "@var $type$ ungültig: Wert muss ein Array sein, welches mindestens eine Zahl an Index 0 enthält",
"placeholders": {
"type": {
"content": "$1"
}
}
},
"styleMetaErrorPreprocessor": {
"message": "Nicht unterstützter @preprocessor: $preprocessor$",
"placeholders": {
@ -980,4 +988,4 @@
"writeStyleForURL": {
"message": "diese URL"
}
}
}

View File

@ -225,4 +225,4 @@
"writeStyleForURL": {
"message": "αυτή την διεύθυνση URL"
}
}
}

View File

@ -1294,5 +1294,38 @@
"writeStyleForURL": {
"message": "this URL",
"description": "Text for link in toolbar pop-up to write a new style for the current URL"
},
"syncDropboxStyles": {
"message": "Dropbox Export"
},
"retrieveDropboxSync": {
"message": "Dropbox Import"
},
"overwriteFileExport": {
"message": "Do you want to overwrite an existing file?"
},
"exportSavedSuccess": {
"message": "File saved with success"
},
"noFileToImport": {
"message": "To import your styles, you should export it first."
},
"connectingDropbox": {
"message": "Connecting Dropbox..."
},
"gettingStyles": {
"message": "Getting all styles..."
},
"zipStyles": {
"message": "Zipping styles..."
},
"unzipStyles": {
"message": "Unzipping styles..."
},
"readingStyles": {
"message": "Reading styles..."
},
"uploadingFile": {
"message": "Uploading File..."
}
}

View File

@ -72,4 +72,4 @@
"usercssConfigIncomplete": {
"message": "The style was updated or deleted after the configuration dialogue was shown. These variables were not saved to avoid corrupting the style's metadata:"
}
}
}

View File

@ -255,11 +255,11 @@
"filteredStyles": {
"message": "$numShown$ mostrados de $numTotal$ en total",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -791,14 +791,14 @@
"styleInstallOverwrite": {
"message": "'$stylename$' ya está instalado ¿Sobrescribirlo?\nVersión: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -998,4 +998,4 @@
"writeStyleForURL": {
"message": "este URL"
}
}
}

View File

@ -255,11 +255,11 @@
"filteredStyles": {
"message": "$numShown$/$numTotal$ kuvatud",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -794,14 +794,14 @@
"styleInstallOverwrite": {
"message": "'$stylename$' on juba paigaldatud. Kas kirjutada üle?\nVersioon: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -1001,4 +1001,4 @@
"writeStyleForURL": {
"message": "see URL"
}
}
}

View File

@ -172,4 +172,4 @@
"updateCompleted": {
"message": "Päivitys suoritettu."
}
}
}

View File

@ -258,11 +258,11 @@
"filteredStyles": {
"message": "$numShown$ montrés sur $numTotal$ au total",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -785,14 +785,14 @@
"styleInstallOverwrite": {
"message": "\"$stylename$\" est déjà installé. L'écraser ?\nVersion : $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -989,4 +989,4 @@
"writeStyleForURL": {
"message": "cette URL"
}
}
}

View File

@ -94,4 +94,4 @@
"deleteStyleLabel": {
"message": "Fuortsmite"
}
}
}

52
_locales/gl/messages.json Normal file
View File

@ -0,0 +1,52 @@
{
"addStyleTitle": {
"message": "Engadir Estilo"
},
"alphaChannel": {
"message": "Opacidade"
},
"appliesAdd": {
"message": "Engadir"
},
"appliesDisplay": {
"message": "Aplica a: $applies$",
"placeholders": {
"applies": {
"content": "$1"
}
}
},
"appliesDisplayTruncatedSuffix": {
"message": "e mais"
},
"appliesDomainOption": {
"message": "URLs no dominio"
},
"appliesLabel": {
"message": "Aplica para"
},
"appliesLineWidgetWarning": {
"message": "Non funciona con CSS minificado"
},
"appliesRegexpOption": {
"message": "URLs que concorden co regexp"
},
"appliesRemove": {
"message": "Suprimir"
},
"appliesSpecify": {
"message": "Especificar"
},
"appliesToEverything": {
"message": "Todo"
},
"appliesUrlPrefixOption": {
"message": "URLs que comecen por"
},
"applyAllUpdates": {
"message": "Aplicar tódalas actualizacións"
},
"author": {
"message": "Autor"
}
}

View File

@ -764,4 +764,4 @@
"writeStyleForURL": {
"message": "הקישור הנוכחי"
}
}
}

View File

@ -12,7 +12,7 @@
"message": "Hozzáadás"
},
"appliesDisplay": {
"message": "A következőre érvényesül:$applies$",
"message": "Érvényes erre:$applies$",
"placeholders": {
"applies": {
"content": "$1"
@ -23,22 +23,22 @@
"message": "és ennél is több"
},
"appliesDomainOption": {
"message": "URL-ek a doménon"
"message": "URL-ek a tartományban"
},
"appliesHelp": {
"message": "Használd az \"A következőre érvényesül\" részt, hogy korlátozd, milyen URL-ekre vonatkozzon az itt lévő kód!"
"message": "Az \"Érvényes erre\" beállítással korlártozható, hogy milyen URL-ekre vonatkozik az itt lévő kód."
},
"appliesLabel": {
"message": "Amire érvényesül"
"message": "Érvényes erre"
},
"appliesLineWidgetLabel": {
"message": "Információ megjelenítése arról, hogy mire van alkalmazva"
},
"appliesLineWidgetWarning": {
"message": "Nem működik minimalizált CSS-szel"
"message": "Nem működik minimalizált CSS-sel"
},
"appliesRegexpOption": {
"message": "Reguláris kifejezésekre (regexp) illeszkedő URL-ek"
"message": "Reguláris kifejezésre (regexp) illeszkedő URL-ek"
},
"appliesRemove": {
"message": "Eltávolítás"
@ -71,7 +71,7 @@
"message": "Stílusok exportálása"
},
"checkAllUpdates": {
"message": "Az összes stílus frissítésének ellenőrzése"
"message": "Összes stílus frissítésének ellenőrzése"
},
"checkAllUpdatesForce": {
"message": "Ellenőrizd újra, nem módosítottam egy stílust sem!"
@ -89,13 +89,13 @@
"message": "Zárójelek és idézőjelek automatikus bezárása"
},
"cm_autoCloseBracketsTooltip": {
"message": "Automatikusan legyen hozzáadva záró jelpár a következők gépelésekor: ()[]{}''\"\""
"message": "Nyitó '([{'zárójel gépelésekor lezáró ')]}' zárójel automatikus hozzáadása"
},
"cm_autocompleteOnTyping": {
"message": "Automatikus kiegészítés gépeléskor"
},
"cm_colorpicker": {
"message": "Színválasztó CSS színekhez"
"message": "Színválasztó CSS-színekhez"
},
"cm_indentWithTabs": {
"message": "Tabulátorok használata intelligens behúzásra"
@ -107,7 +107,7 @@
"message": "Automatikus sortörés"
},
"cm_matchHighlight": {
"message": "Kijelöl"
"message": "Kijelölés"
},
"cm_matchHighlightSelection": {
"message": "Csak kiválasztás"
@ -125,7 +125,7 @@
"message": "Példák kifejezésekre: .valami-2 #aabbcc 0.32 !important\nAmikor ki van kapcsolva: a központosítással elválasztott szavak ki lesznek jelölve."
},
"cm_smartIndent": {
"message": "Intelligens behúzás használata"
"message": "Intelligens behúzás"
},
"cm_tabSize": {
"message": "Tabulátorméret"
@ -200,7 +200,7 @@
"message": "Tervezd újra a webet a Stylus stíluskezelővel. A Stylus lehetővé teszi a témák és egyéni külsők egyszerű telepítését sok népszerű oldalhoz."
},
"disableAllStyles": {
"message": "Az összes stílus kikapcsolása"
"message": "Összes stílus kikapcsolása"
},
"disableStyleLabel": {
"message": "Letiltás"
@ -255,11 +255,11 @@
"filteredStyles": {
"message": "$numShown$ mutatva $numTotal$-ból/-ből",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -321,10 +321,10 @@
"message": "Írj be egy parancsot"
},
"helpKeyMapHotkey": {
"message": "Gyorsgomb"
"message": "Gyorsbillentyű"
},
"importAppendLabel": {
"message": "Hozzáadás stílushoz"
"message": "Hozzáfűzés stílushoz"
},
"importAppendTooltip": {
"message": "Az importált stílus hozzáadása a jelenlegi stílushoz"
@ -357,10 +357,10 @@
"message": "metainfó frissítve"
},
"importReportTitle": {
"message": "A stílusok importálása befejeződött"
"message": "A stílusok importálása befejeződött."
},
"importReportUnchanged": {
"message": "Semmi sem változott."
"message": "Nincs változás."
},
"importReportUndone": {
"message": "stílusok visszavonva"
@ -384,7 +384,7 @@
"message": "Frissítés telepítése"
},
"installUpdateFrom": {
"message": "A stílus most a következő helyről frissül: $url$",
"message": "A stílus jelenleg innen frissül: $url$",
"placeholders": {
"url": {
"content": "$1"
@ -398,7 +398,7 @@
"message": "Licenc"
},
"linkGetHelp": {
"message": "Kérj segítséget"
"message": "Segítség kérése"
},
"linkGetStyles": {
"message": "Szerezz be stílusokat"
@ -426,10 +426,10 @@
}
},
"linterConfigTooltip": {
"message": "Kattints ennek a linternek a beállításához"
"message": "Linter beállítása"
},
"linterInvalidConfigError": {
"message": "Nincs mentve ezek miatt az érvénytelen beállítások miatt:"
"message": "Nincs mentve a következő érvénytelen beállítások miatt:"
},
"linterIssues": {
"message": "Problémák"
@ -443,31 +443,31 @@
}
},
"linterJSONError": {
"message": "Érvénytelen JSON formátum"
"message": "Érvénytelen JSON-formátum"
},
"linterResetMessage": {
"message": "Egy véletlen visszaállítás visszavonásához nyomj Ctrl-Z-t (vagy Cmd-Z) a szövegdobozon belül)"
},
"linterRulesLink": {
"message": "Lista az összes stílusról"
"message": "Összes szabály listája"
},
"liveReloadError": {
"message": "Hiba történt a fájl figyelése közben"
},
"liveReloadInstallHint": {
"message": "A valós idejű újratöltés engedélyezve van, így a telepített stílus automatikusan frissítve lesz kűlső változtatások során amíg ez a fül és a forrásfájlt tartalmazó fül nyitva van."
"message": "A valós idejű újratöltés engedélyezve van, így a telepített stílus automatikusan frissül külső változások során, amíg ez a fül és a forrásfájlt tartalmazó fül nyitva van."
},
"liveReloadLabel": {
"message": "Valós idejű újratöltés"
},
"manageFavicons": {
"message": "Faviconok az alkalmazási oszlopban"
"message": "Faviconok az 'Érvényes erre' oszlopban"
},
"manageFaviconsGray": {
"message": "Szürke mód"
"message": "Megjelenítés szürkítve"
},
"manageFaviconsHelp": {
"message": "A Stylus egy külső szolgáltatást használ (https://www.google.com/s2/favicons)"
"message": "A Stylus külső szolgáltatást használ (https://www.google.com/s2/favicons)"
},
"manageFilters": {
"message": "Szűrők"
@ -476,13 +476,13 @@
"message": "Telepített stílusok"
},
"manageMaxTargets": {
"message": "Megjelenítendő célok száma"
"message": "'Érvényes erre' elemek kijelzendő száma"
},
"manageNewStyleAsUsercss": {
"message": "Usercss-ként"
},
"manageNewUI": {
"message": "Az új kezelési felületkiosztás"
"message": "Új kezelői felület"
},
"manageOnlyDisabled": {
"message": "Csak letiltott stílusok"
@ -497,13 +497,13 @@
"message": "Csak helyileg létrehozott stílusok"
},
"manageOnlyLocalTooltip": {
"message": "(a stílusok nem egy userstyles.org oldalon lettek telepítve)"
"message": "(a stílusok nem a userstyles.org egyik oldaláról települtek)"
},
"manageOnlyNonUsercss": {
"message": "Csak nem Usercss stílusok"
},
"manageOnlyUpdates": {
"message": "Csak frissíthetőek vagy problémásak"
"message": "Csak a frissíthetők vagy problémásak"
},
"manageOnlyUsercss": {
"message": "Csak Usercss stílusok"
@ -524,7 +524,7 @@
"message": "Beállítások"
},
"openStylesManager": {
"message": "A frissítéskezelő megnyitása"
"message": "Stíluskezelő megnyitása"
},
"optionsActions": {
"message": "Műveletek"
@ -533,13 +533,13 @@
"message": "Haladó"
},
"optionsAdvancedContextDelete": {
"message": "Delete hozzáadása a gyorsmenühöz"
"message": "'Törlés' parancs a szerkesztő helyi menüjében"
},
"optionsAdvancedExposeIframes": {
"message": "iframe-ek kitevése HTML[stylus-iframe]-en keresztül"
},
"optionsAdvancedExposeIframesNote": {
"message": "Engedélyezi a legfelsőbb szintű domain elérését\nmindegyik iframe-ben. Lehetővé teszi az olyan\niframe-specifikus CSS írását, mint:\nhtml[stylus-iframe$=\"twitter.com\"] h1 { display:none }"
"message": "A legfelsőbb szintű tartomány elérésének engedélyezése\nmindegyik iframe-ben. Lehetővé teszi az olyan\niframe-specifikus CSS írását, mint pl.:\nhtml[stylus-iframe$=\"twitter.com\"] h1 { display:none }"
},
"optionsAdvancedNewStyleAsUsercss": {
"message": "Új stílus írása usercss-ként"
@ -557,13 +557,13 @@
"message": "Az összes frissítés ellenőrzése és telepítése"
},
"optionsCustomizeBadge": {
"message": "Jelvény az eszköztárikonon"
"message": "Ikon képe az eszköztáron"
},
"optionsCustomizeIcon": {
"message": "Eszköztárikon"
},
"optionsCustomizePopup": {
"message": "Felugró"
"message": "Felugró ablak"
},
"optionsCustomizeUpdate": {
"message": "Frissítések"
@ -587,13 +587,13 @@
"message": "Felugró ablak szélessége (pixelben)"
},
"optionsReset": {
"message": "Beállítások visszaállítása alapértelmezett értékekre."
"message": "Beállítások visszaállítása alapértelmezett értékre"
},
"optionsResetButton": {
"message": "Beállítások visszaállítása alapra"
"message": "Alapértelmezés visszaállítása"
},
"optionsSubheading": {
"message": "Még több beállítás"
"message": "További beállítások"
},
"optionsUpdateImportNote": {
"message": "Amikor régebbi verzióból vagy a Stylishból importálsz stílusokat, egyszer manuálisan frissítsd a stílusokat a stíluskezelőben, hogy megbizonyosodj afelől, hogy mindegyik frissítve van!"
@ -620,19 +620,19 @@
"message": "A Stylus nem tudta elemezni a usercss-t"
},
"popupBorders": {
"message": "Fehér szegélyek használata két oldalt"
"message": "Fehér szegély az oldalakon"
},
"popupBordersTooltip": {
"message": "Hasznos az új Chromehoz létrehozott sötét témákhoz, mert nem színezi át az oldalszegélyeket"
"message": "Hasznos az új Chrome sötét témáinál, mert nem színezi át az oldalszegélyeket"
},
"popupHotkeysInfo": {
"message": "<1>-<9>, <0>, a numpaden is - be-/kikapcsolja az n-nedik stílust (a 0 10-et jelent)\n<A>-<Z> az adott betűvel kezdődő első stílust kapcsolja be/ki \n<Shift> kapcsolgatás helyett megnyitja a szerkesztőt\n<Numpad +> listázott stílusokat engedélyez\n<Numpad > listázott stílusokat tilt le\n<Numpad *> és <`> (fordított félidézőjel) - kezdeti állapotban engedélyezett stílusokat kapcsol; nem vonatkozik azokra a stílusokra, amiket később engedélyeztél, mialatt a felugró ablakocska nyitva volt, hogy vissza tudd állítani a kezdeti kiválasztást tesztelés után: egyszerűen tilts le mindent, majd pl. <Numpad > vagy <Numpad *>\nTovábbi információ a wikiben"
},
"popupHotkeysTooltip": {
"message": "Kattints az elérhető gyorsbillentyűk megtekintéséhez"
"message": "Elérhető gyorsbillentyűk megtekintése"
},
"popupManageTooltip": {
"message": "Shift-kattintás vagy jobb kattintás megnyitja a stíluskezelőt a jelenlegi oldalra érvényesülő stílusokkal"
"message": "Shift+kattintás vagy jobb kattintás: a stíluskezelő megnyitása a jelenlegi oldalra érvényes stílusokkal"
},
"popupOpenEditInWindow": {
"message": "Szerkesztő megnyitása új ablakban"
@ -641,7 +641,7 @@
"message": "A fül a böngésző ablakától történő leválasztásával is engedélyezhető, és letiltható a fül egy másik ablakhoz való hozzácsatolásával."
},
"popupStylesFirst": {
"message": "Parancsok előtti stílusok"
"message": "Stílusnevek a parancsok előtt"
},
"prefShowBadge": {
"message": "A jelenlegi oldalon aktív stílusok száma"
@ -722,28 +722,28 @@
"message": "Gyorsbillentyűk megadása"
},
"sortDateNewestFirst": {
"message": "a legújabb elöl"
"message": "újabb elöl"
},
"sortDateOldestFirst": {
"message": "a legrégebbi elöl"
"message": "régebbi elöl"
},
"sortLabel": {
"message": "Válaszd ki, hogyan szeretnéd sorba rendezni a telepített stílusokat"
"message": "Telepített stílusok sorbarendezésének módja"
},
"sortLabelTitleAsc": {
"message": "Cím növekvő sorrendben"
"message": "Cím - növekvő sorrend"
},
"sortLabelTitleDesc": {
"message": "Cím csökkenő sorrendben"
"message": "Cím - csökkenő sorrend"
},
"sortStylesHelp": {
"message": "A legördülő menüben válaszd ki, hogyan szeretnéd sorba rendezni a telepített bejegyzéseket. Az alapértelmezett beállítás növekvő sorrend (A-tól Z-ig) a bejegyzések címei szerint. A „Cím csökkenő sorrendben” csoportban megadott rendezési módok csökkenő sorrendet (Z-től A-ig) alkalmaznak a címre.\nMás beállítások azt is lehetővé teszik, hogy több szempont alapján rendezd a bejegyzéseket. Elképzelheted ezt úgy, mint egy többoszlopos rendezési táblázatot, amelyben minden egyes (a plusz jelek között) kiválasztott kategória egy oszlopot vagy egy csoportot jelképez.\nPéldául ha az van beállítva, hogy „Engedélyezve (első) + Cím”, az engedélyezett bejegyzések kerülnek a lista tetejére, aztán az engedélyezett és a letiltott bejegyzések címei külön-külön növekvő sorrendbe A-tól Z-ig) vannak rendezve."
"message": "A legördülő menüben válaszhatjuk ki, hogyan szeretnénk sorbarendezni a telepített stílusok bejegyzéseit. Az alapértelmezett beállítás a bejegyzések címei szerinti növekvő (A-tól Z-ig) sorrend. A „Cím - csökkenő sorrend” csoportban megadott rendezési módok csökkenő (Z-től A-ig) sorrendben rendezik a címeket.\nEgyéb beállításokkal több szempont alapján is rendezhetők a bejegyzések. Tekintsünk erre úgy, mint egy többoszlopos, rendezhető táblázatra, amelyben minden egyes (a plusz jelek között) kiválasztott kategória egy oszlopot vagy egy csoportot jelképez.\nPéldául, ha az van beállítva, hogy „Engedélyezve (első) + Cím”, az engedélyezett bejegyzések kerülnek a lista tetejére, majd az engedélyezett és a letiltott bejegyzések címei külön-külön, növekvő (A-tól Z-ig) sorrendben jelennek meg."
},
"sortStylesHelpTitle": {
"message": "Tartalom rendezése"
},
"styleBadRegexp": {
"message": "Érvénytelen regexp."
"message": "Érvénytelen reguláris kifejezés."
},
"styleBeautify": {
"message": "Csinosít"
@ -788,14 +788,14 @@
"styleInstallOverwrite": {
"message": "„$stylename$” már telepítve van. Felülírod?\nVerzió: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -833,28 +833,28 @@
"message": "Írj be egy nevet!"
},
"styleMozillaFormatHeading": {
"message": "Mozilla formátum"
"message": "Mozilla-formátum"
},
"styleNotAppliedRegexpProblemTooltip": {
"message": "A stílus nem lett alkalmazva a „regexp()” helytelen használata miatt"
},
"styleRegexpInvalidExplanation": {
"message": "Egyes „regexp()” szabályokat nem lehetett lefordítani."
"message": "Néhány „regexp()” szabály nem lefordítható."
},
"styleRegexpPartialExplanation": {
"message": "Ez a stílus olyan részlegesen illeszkedő reguláris kifejezéseket használ, melyek sértik a<a href='https://developer.mozilla.org/docs/Web/CSS/@document'>CSS4@dokumentumspecifikációt</a>, mely szerint egy teljes URL-illeszkedésre van szükség. Az érintett CSS-szekciók nem kerültek alkalmazásra az oldalon. Ez a stílus valószínűleg a Stylish Chrome-kiegészítőben lett létrehozva, amely helytelenül ellenőrzi a „regexp()” szabályokat az első verziótól fogva (ismert hiba)."
"message": "A stílus olyan részlegesen illeszkedő reguláris kifejezéseket használ, amelyek sértik a<a href='https://developer.mozilla.org/docs/Web/CSS/@document'>CSS4@dokumentumspecifikációt</a>, amely megköveteli az URL teljes illeszkedését. Az érintett CSS-szekciók nem kerültek alkalmazásra az oldalon. A stílus valószínűleg a Stylish-for-Chrome kiegészítőben készült, amely helytelenül ellenőrzi a „regexp()” szabályokat a legelső verziótól fogva (ismert hiba)."
},
"styleRegexpProblemTooltip": {
"message": "A nem alkalmazott szeckiók száma helytelen 'regexp()' használat miatt"
},
"styleRegexpTestButton": {
"message": "RegExp teszt"
"message": "RegExp tesztelése"
},
"styleRegexpTestFull": {
"message": "Illeszkedő fülek"
},
"styleRegexpTestInvalid": {
"message": "Kihagyott érvénytelen reguláris kifejezések"
"message": "Kihagyott, érvénytelen reguláris kifejezések"
},
"styleRegexpTestNone": {
"message": "Nincs illeszkedő fül"
@ -995,4 +995,4 @@
"writeStyleForURL": {
"message": "ehhez az URL-hez"
}
}
}

View File

@ -79,6 +79,9 @@
"clickToUninstall": {
"message": "Clica per disinstallare"
},
"cm_autoCloseBrackets": {
"message": "Chiudi automaticamente parentesi e virgolette"
},
"cm_autocompleteOnTyping": {
"message": "Completamento automatico durante digitazione"
},
@ -86,7 +89,7 @@
"message": "Selezionatore colore per colori CSS"
},
"cm_indentWithTabs": {
"message": "Usa schede con indentazione intellingente"
"message": "Usa tabulazioni con indentazione intellingente"
},
"cm_keyMap": {
"message": "Mappa caratteri"
@ -101,7 +104,7 @@
"message": "Usa indentazione intelligente"
},
"cm_tabSize": {
"message": "Dimensione scheda"
"message": "Dimensione tabulazione"
},
"cm_theme": {
"message": "Tema"
@ -207,11 +210,11 @@
"filteredStyles": {
"message": "$numShown$ mostrati di $numTotal$ totali",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -523,6 +526,9 @@
"search": {
"message": "Cerca"
},
"searchNumberOfResults": {
"message": "Numero di occorrenze"
},
"searchResultInstallCount": {
"message": "Installazioni totali"
},
@ -611,14 +617,14 @@
"styleInstallOverwrite": {
"message": "'$stylename$' è già installato. Vuoi sovrascriverlo?\nVersione: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -727,4 +733,4 @@
"writeStyleForURL": {
"message": "questo URL"
}
}
}

View File

@ -255,11 +255,11 @@
"filteredStyles": {
"message": "$numTotal$ 件中の $numShown$ 件を表示",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -797,14 +797,14 @@
"styleInstallOverwrite": {
"message": "「$stylename$」はすでにインストール済みです。上書きしますか?\nバージョン: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -819,6 +819,14 @@
}
}
},
"styleMetaErrorRangeOrNumber": {
"message": "不正な @var $type$: 最低でも1個の数値を持つ配列である必要があります",
"placeholders": {
"type": {
"content": "$1"
}
}
},
"styleMetaErrorPreprocessor": {
"message": "未サポートの @preprocessor: $preprocessor$",
"placeholders": {
@ -1001,4 +1009,4 @@
"writeStyleForURL": {
"message": "このURL"
}
}
}

View File

@ -255,11 +255,11 @@
"filteredStyles": {
"message": "$numShown$ van de $numTotal$ getoond",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -782,14 +782,14 @@
"styleInstallOverwrite": {
"message": "$stylename$ is al geïnstalleerd. Overschrijven?\nVersie: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -804,6 +804,14 @@
}
}
},
"styleMetaErrorRangeOrNumber": {
"message": "Ongeldige @var $type$: de waarde moet een reeks zijn die minimaal één getal bevat bij index nul",
"placeholders": {
"type": {
"content": "$1"
}
}
},
"styleMetaErrorPreprocessor": {
"message": "Niet-ondersteunde @preprocessor: $preprocessor$",
"placeholders": {
@ -989,4 +997,4 @@
"writeStyleForURL": {
"message": "deze URL"
}
}
}

View File

@ -261,11 +261,11 @@
"filteredStyles": {
"message": "Pokazano $numShown$ z sumy $numTotal$",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -800,14 +800,14 @@
"styleInstallOverwrite": {
"message": "'$stylename$' jest już zainstalowany. Zastąpić?\nWersja: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -822,6 +822,14 @@
}
}
},
"styleMetaErrorRangeOrNumber": {
"message": "Nieprawidłowa wartość @var $type$: musi być tablicą zawierającą co najmniej jedną liczbę w punkcie zerowym",
"placeholders": {
"type": {
"content": "$1"
}
}
},
"styleMetaErrorPreprocessor": {
"message": "Nieobsługiwany @preprocessor: $preprocessor$",
"placeholders": {
@ -1007,4 +1015,4 @@
"writeStyleForURL": {
"message": "tego adresu URL"
}
}
}

View File

@ -271,4 +271,4 @@
"writeStyleForURL": {
"message": "esse URL"
}
}
}

View File

@ -249,11 +249,11 @@
"filteredStyles": {
"message": "$numShown$ apresentado(s) de $numTotal$total",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -782,14 +782,14 @@
"styleInstallOverwrite": {
"message": "$stylename$já está instalado. Substituir?\nVersão:$oldVersion$-> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -989,4 +989,4 @@
"writeStyleForURL": {
"message": "este URL"
}
}
}

View File

@ -222,11 +222,11 @@
"filteredStyles": {
"message": "$numShown$ vizualizabile din $numTotal$ ",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -725,14 +725,14 @@
"styleInstallOverwrite": {
"message": "'$stylename$' este deja instalată. Scrieți peste?\nVersiune: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -926,4 +926,4 @@
"writeStyleForURL": {
"message": "acest URL"
}
}
}

View File

@ -261,11 +261,11 @@
"filteredStyles": {
"message": "найдено $numShown$ из $numTotal$всего",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -803,14 +803,14 @@
"styleInstallOverwrite": {
"message": "'$stylename$' уже установлен. Обновить?\nВерсии: $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -1010,4 +1010,4 @@
"writeStyleForURL": {
"message": "этого адреса"
}
}
}

View File

@ -320,4 +320,4 @@
"writeStyleForURL": {
"message": "ову УРЛ адресу"
}
}
}

View File

@ -402,4 +402,4 @@
"writeStyleForURL": {
"message": "denna URL"
}
}
}

View File

@ -52,4 +52,4 @@
"styleSectionsTitle": {
"message": "విభాగాలు"
}
}
}

View File

@ -157,4 +157,4 @@
"updateCompleted": {
"message": "Güncelleme tamamlandı."
}
}
}

View File

@ -168,4 +168,4 @@
"updateCompleted": {
"message": "更新完成."
}
}
}

View File

@ -255,11 +255,11 @@
"filteredStyles": {
"message": "已显示 $numShown$ 个,总共 $numTotal$ 个",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -776,14 +776,14 @@
"styleInstallOverwrite": {
"message": "'$stylename$' 已经安装,要覆盖吗?\n版本 $oldVersion$ -> $newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -980,4 +980,4 @@
"writeStyleForURL": {
"message": "这个URL"
}
}
}

View File

@ -206,7 +206,7 @@
"message": "用Stylus一個用戶樣式管理器重塑網頁。 Stylus 讓你能為诸多主流網站輕鬆的安裝主題和皮膚。"
},
"disableAllStyles": {
"message": "用所有樣式"
"message": "用所有樣式"
},
"disableStyleLabel": {
"message": "停用"
@ -261,11 +261,11 @@
"filteredStyles": {
"message": "$numShown$ 個已顯示,總共 $numTotal$ 個",
"placeholders": {
"numShown": {
"content": "$1"
},
"numTotal": {
"content": "$2"
},
"numShown": {
"content": "$1"
}
}
},
@ -800,14 +800,14 @@
"styleInstallOverwrite": {
"message": "「$stylename$」已安裝。要覆寫嗎?\n版本$oldVersion$→$newVersion$",
"placeholders": {
"stylename": {
"content": "$1"
},
"newVersion": {
"content": "$3"
},
"oldVersion": {
"content": "$2"
},
"stylename": {
"content": "$1"
}
}
},
@ -822,6 +822,14 @@
}
}
},
"styleMetaErrorRangeOrNumber": {
"message": "無效的 @var $type$:值必須為在索引零處包含至少一個數字的陣列",
"placeholders": {
"type": {
"content": "$1"
}
}
},
"styleMetaErrorPreprocessor": {
"message": "不支援的 @preprocessor$preprocessor$",
"placeholders": {
@ -1007,4 +1015,4 @@
"writeStyleForURL": {
"message": "此網址"
}
}
}

View File

@ -161,10 +161,17 @@
<script src="manage/updater-ui.js" async></script>
<script src="manage/object-diff.js" async></script>
<script src="manage/import-export.js" async></script>
<script src="manage/incremental-search.js" async></script>
<script src="msgbox/msgbox.js" async></script>
<script src="js/sections-equal.js" async></script>
<script src="js/storage-util.js" async></script>
<script src="sync/vendor/dropbox/dropbox-sdk.js" async></script>
<script src="sync/vendor/zipjs/zip.js" defer></script>
<script src="sync/compress-text.js" defer></script>
<script src="sync/cross-browser-functions.js" defer></script>
<script src="sync/import-export-dropbox.js" async></script>
</head>
<body id="stylus-manage" i18n-dragndrop-hint="dragDropMessage">
@ -364,8 +371,30 @@
<summary><h2 id="backup-title" i18n-text="backupButtons"></h2></summary>
<span id="backup-message" i18n-text="backupMessage"></span>
<div id="backup-buttons">
<button id="file-all-styles" i18n-text="bckpInstStyles"></button>
<button id="unfile-all-styles" i18n-text="retrieveBckp"></button>
<div class="dropdown">
<button class="dropbtn">
<span>Export</span>
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
</button>
<div class="dropdown-content">
<a href="#" id="file-all-styles" i18n-text="bckpInstStyles"></a>
<a href="#" id="sync-dropbox-export" i18n-text="syncDropboxStyles"></a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">
<span>Import</span>
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
</button>
<div class="dropdown-content">
<a href="#" id="unfile-all-styles" i18n-text="retrieveBckp"></a>
<a href="#" id="sync-dropbox-import" i18n-text="retrieveDropboxSync"></a>
</div>
</div>
</div>
</details>

View File

@ -1047,6 +1047,54 @@ input[id^="manage.newUI"] {
text-overflow: ellipsis;
}
/* export/import buttons */
#backup-buttons .dropbtn {
padding: 3px 7px;
cursor: pointer;
text-overflow: inherit;
}
#backup-buttons .dropbtn span {
display: inline-block;
margin-right: 7px;
}
#backup-buttons .dropdown {
position: relative;
display: inline-block;
}
#backup-buttons .dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
#backup-buttons .dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
#backup-buttons .dropdown-content a:hover {
/* background-color: #f2f2f2 */
background-color: #e9e9e9
}
#backup-buttons .dropdown:hover .dropdown-content {
display: block;
}
#backup-buttons .dropdown:hover .dropbtn {
background-color: hsl(0, 0%, 95%);
border-color: hsl(0, 0%, 52%);
/* background-color: #3e8e41; */
}
/* sort font */
@font-face {
font-family: 'sorticon';

View File

@ -1,6 +1,6 @@
{
"name": "Stylus",
"version": "1.4.22",
"version": "1.4.23",
"minimum_chrome_version": "49",
"description": "__MSG_description__",
"homepage_url": "https://add0n.com/stylus.html",
@ -19,6 +19,7 @@
"contextMenus",
"storage",
"alarms",
"identity",
"<all_urls>"
],
"background": {

View File

@ -1,6 +1,6 @@
{
"name": "Stylus",
"version": "1.4.22",
"version": "1.4.23",
"description": "Redesign the web with Stylus, a user styles manager",
"license": "GPL-3.0-only",
"repository": "openstyles/stylus",
@ -17,15 +17,18 @@
"semver-bundle": "^0.1.1",
"stylelint-bundle": "^8.0.0",
"stylus-lang-bundle": "^0.54.5",
"updates": "^5.1.2"
"updates": "^5.1.2",
"webext-tx-fix": "^0.3.1"
},
"scripts": {
"lint": "eslint **/*.js --cache || exit 0",
"update": "npm run update-node && npm run update-main",
"update-quick": "updates -u && npm update && npm run update-main",
"update-main": "npm run update-versions && npm run update-codemirror",
"update-locales": "tx pull --all && webext-tx-fix",
"update-main": "npm run update-versions && npm run update-vendor",
"update-node": "updates -u && node tools/remove-modules.js && npm install",
"update-codemirror": "node tools/update-libraries.js && node tools/update-codemirror-themes.js",
"update-transifex": "tx push -s",
"update-vendor": "node tools/update-libraries.js && node tools/update-codemirror-themes.js",
"update-versions": "node tools/update-versions",
"zip": "npm run update-versions && node tools/zip.js"
}

41
sync/compress-text.js Normal file
View File

@ -0,0 +1,41 @@
/* global messageBox */
/* global zip */
'use strict';
onDOMready().then(() => {
zip.workerScriptsPath = '/sync/vendor/zipjs/';
});
/**
* @param {String} filename
* @param {String} text content of the file as text
* @returns {Promise<Blob>} resolves to a blob object representing the zip file
*/
function createZipFileFromText(filename, text) {
return new Promise((resolve, reject) => {
zip.createWriter(new zip.BlobWriter('application/zip'), writer => {
writer.add(filename, new zip.TextReader(text), function () {
writer.close(blob => {
resolve(blob);
});
});
}, reject);
});
}
/**
* @param {Object} blob object of zip file
* @returns {Promise<String>} resolves to a string the content of the first file of the zip
*/
function readZipFileFromBlob(blob) {
return new Promise((resolve, reject) => {
zip.createReader(new zip.BlobReader(blob), zipReader => {
zipReader.getEntries(entries => {
entries[0].getData(new zip.BlobWriter('text/plain'), data => {
zipReader.close();
resolve(data);
});
});
}, reject);
});
}

View File

@ -0,0 +1,24 @@
'use strict';
/**
* @returns {String} returns a redirect URL to be used in |launchWebAuthFlow|
*/
function getRedirectUrlAuthFlow() {
const browserApi = typeof browser === 'undefined' ? chrome : browser;
return browserApi.identity.getRedirectURL();
}
/**
* @param {Object} details based on chrome api
* @param {string} details.url url that initiates the auth flow
* @param {boolean} details.interactive if it is true a window will be displayed
* @return {Promise} returns the url containing the token for extraction
*/
function launchWebAuthFlow(details) {
if (typeof browser === 'undefined') {
return new Promise(resolve => {
chrome.identity.launchWebAuthFlow(details, resolve);
});
}
return browser.identity.launchWebAuthFlow(details);
}

View File

@ -0,0 +1,163 @@
/* global messageBox Dropbox createZipFileFromText readZipFileFromBlob launchWebAuthFlow getRedirectUrlAuthFlow importFromString resolve */
'use strict';
const DROPBOX_API_KEY = 'zg52vphuapvpng9';
const FILENAME_ZIP_FILE = 'stylus.json';
const DROPBOX_FILE = 'stylus.zip';
const API_ERROR_STATUS_FILE_NOT_FOUND = 409;
const HTTP_STATUS_CANCEL = 499;
function messageProgressBar(data) {
return messageBox({
title: `${data.title}`,
className: 'config-dialog',
contents: [
$create('p', data.text)
],
buttons: [{
textContent: t('confirmClose'),
dataset: {cmd: 'close'},
}],
}).then(() => {
document.body.style.minWidth = '';
document.body.style.minHeight = '';
});
}
function hasDropboxAccessToken() {
return chromeLocal.getValue('dropbox_access_token');
}
function requestDropboxAccessToken() {
const client = new Dropbox.Dropbox({clientId: DROPBOX_API_KEY});
const authUrl = client.getAuthenticationUrl(getRedirectUrlAuthFlow());
return launchWebAuthFlow({url: authUrl, interactive: true})
.then(urlReturned => {
const params = new URLSearchParams(new URL(urlReturned).hash.replace('#', ''));
chromeLocal.setValue('dropbox_access_token', params.get('access_token'));
return params.get('access_token');
});
}
function uploadFileDropbox(client, stylesText) {
return client.filesUpload({path: '/' + DROPBOX_FILE, contents: stylesText});
}
$('#sync-dropbox-export').onclick = () => {
const title = t('syncDropboxStyles');
messageProgressBar({title: title, text: t('connectingDropbox')});
hasDropboxAccessToken()
.then(token => token || requestDropboxAccessToken())
.then(token => {
const client = new Dropbox.Dropbox({
clientId: DROPBOX_API_KEY,
accessToken: token
});
return client.filesDownload({path: '/' + DROPBOX_FILE})
.then(() => messageBox.confirm(t('overwriteFileExport')))
.then(ok => {
// deletes file if user want to
if (!ok) {
return Promise.reject({status: HTTP_STATUS_CANCEL});
}
return client.filesDelete({path: '/' + DROPBOX_FILE});
})
// file deleted with success, get styles and create a file
.then(() => {
messageProgressBar({title: title, text: t('gettingStyles')});
return API.getStyles().then(styles => JSON.stringify(styles, null, '\t'));
})
// create zip file
.then(stylesText => {
messageProgressBar({title: title, text: t('zipStyles')});
return createZipFileFromText(FILENAME_ZIP_FILE, stylesText);
})
// create file dropbox
.then(zipedText => {
messageProgressBar({title: title, text: t('uploadingFile')});
return uploadFileDropbox(client, zipedText);
})
// gives feedback to user
.then(() => messageProgressBar({title: title, text: t('exportSavedSuccess')}))
// handle not found cases and cancel action
.catch(error => {
console.log(error);
// saving file first time
if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
API.getStyles()
.then(styles => {
messageProgressBar({title: title, text: t('gettingStyles')});
return JSON.stringify(styles, null, '\t');
})
.then(stylesText => {
messageProgressBar({title: title, text: t('zipStyles')});
return createZipFileFromText(FILENAME_ZIP_FILE, stylesText);
})
.then(zipedText => {
messageProgressBar({title: title, text: t('uploadingFile')});
return uploadFileDropbox(client, zipedText);
})
.then(() => messageProgressBar({title: title, text: t('exportSavedSuccess')}))
.catch(err => messageBox.alert(err));
return;
}
// user cancelled the flow
if (error.status === HTTP_STATUS_CANCEL) {
return;
}
console.error(error);
});
});
};
$('#sync-dropbox-import').onclick = () => {
const title = t('retrieveDropboxSync');
messageProgressBar({title: title, text: t('connectingDropbox')});
hasDropboxAccessToken()
.then(token => token || requestDropboxAccessToken())
.then(token => {
const client = new Dropbox.Dropbox({
clientId: DROPBOX_API_KEY,
accessToken: token
});
return client.filesDownload({path: '/' + DROPBOX_FILE})
.then(response => {
messageProgressBar({title: title, text: t('unzipStyles')});
return readZipFileFromBlob(response.fileBlob);
})
.then(zipedFileBlob => {
messageProgressBar({title: title, text: t('readingStyles')});
document.body.style.cursor = 'wait';
const fReader = new FileReader();
fReader.onloadend = event => {
const text = event.target.result;
const maybeUsercss = !/^[\s\r\n]*\[/.test(text) &&
(text.includes('==UserStyle==') || /==UserStyle==/i.test(text));
(!maybeUsercss ?
importFromString(text) :
getOwnTab().then(tab => {
tab.url = URL.createObjectURL(new Blob([text], {type: 'text/css'}));
return API.installUsercss({direct: true, tab})
.then(() => URL.revokeObjectURL(tab.url));
})
).then(numStyles => {
document.body.style.cursor = '';
resolve(numStyles);
});
};
fReader.readAsText(zipedFileBlob, 'utf-8');
})
.catch(error => {
// no file
if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
messageBox.alert(t('noFileToImport'));
return;
}
messageBox.alert(error);
});
});
};

20
sync/vendor/dropbox/LICENSE vendored Executable file
View File

@ -0,0 +1,20 @@
Copyright (c) 2016 Dropbox Inc., http://www.dropbox.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

5190
sync/vendor/dropbox/dropbox-sdk.js vendored Normal file

File diff suppressed because it is too large Load Diff

22
sync/vendor/zipjs/LICENSE vendored Executable file
View File

@ -0,0 +1,22 @@
/*
Copyright (c) 2013 Gildas Lormeau. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

2060
sync/vendor/zipjs/deflate.js vendored Executable file

File diff suppressed because it is too large Load Diff

2155
sync/vendor/zipjs/inflate.js vendored Executable file

File diff suppressed because it is too large Load Diff

153
sync/vendor/zipjs/z-worker.js vendored Executable file
View File

@ -0,0 +1,153 @@
/* jshint worker:true */
(function main(global) {
"use strict";
if (global.zWorkerInitialized)
throw new Error('z-worker.js should be run only once');
global.zWorkerInitialized = true;
addEventListener("message", function(event) {
var message = event.data, type = message.type, sn = message.sn;
var handler = handlers[type];
if (handler) {
try {
handler(message);
} catch (e) {
onError(type, sn, e);
}
}
//for debug
//postMessage({type: 'echo', originalType: type, sn: sn});
});
var handlers = {
importScripts: doImportScripts,
newTask: newTask,
append: processData,
flush: processData,
};
// deflater/inflater tasks indexed by serial numbers
var tasks = {};
function doImportScripts(msg) {
if (msg.scripts && msg.scripts.length > 0)
importScripts.apply(undefined, msg.scripts);
postMessage({type: 'importScripts'});
}
function newTask(msg) {
var CodecClass = global[msg.codecClass];
var sn = msg.sn;
if (tasks[sn])
throw Error('duplicated sn');
tasks[sn] = {
codec: new CodecClass(msg.options),
crcInput: msg.crcType === 'input',
crcOutput: msg.crcType === 'output',
crc: new Crc32(),
};
postMessage({type: 'newTask', sn: sn});
}
// performance may not be supported
var now = global.performance ? global.performance.now.bind(global.performance) : Date.now;
function processData(msg) {
var sn = msg.sn, type = msg.type, input = msg.data;
var task = tasks[sn];
// allow creating codec on first append
if (!task && msg.codecClass) {
newTask(msg);
task = tasks[sn];
}
var isAppend = type === 'append';
var start = now();
var output;
if (isAppend) {
try {
output = task.codec.append(input, function onprogress(loaded) {
postMessage({type: 'progress', sn: sn, loaded: loaded});
});
} catch (e) {
delete tasks[sn];
throw e;
}
} else {
delete tasks[sn];
output = task.codec.flush();
}
var codecTime = now() - start;
start = now();
if (input && task.crcInput)
task.crc.append(input);
if (output && task.crcOutput)
task.crc.append(output);
var crcTime = now() - start;
var rmsg = {type: type, sn: sn, codecTime: codecTime, crcTime: crcTime};
var transferables = [];
if (output) {
rmsg.data = output;
transferables.push(output.buffer);
}
if (!isAppend && (task.crcInput || task.crcOutput))
rmsg.crc = task.crc.get();
// posting a message with transferables will fail on IE10
try {
postMessage(rmsg, transferables);
} catch(ex) {
postMessage(rmsg); // retry without transferables
}
}
function onError(type, sn, e) {
var msg = {
type: type,
sn: sn,
error: formatError(e)
};
postMessage(msg);
}
function formatError(e) {
return { message: e.message, stack: e.stack };
}
// Crc32 code copied from file zip.js
function Crc32() {
this.crc = -1;
}
Crc32.prototype.append = function append(data) {
var crc = this.crc | 0, table = this.table;
for (var offset = 0, len = data.length | 0; offset < len; offset++)
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
this.crc = crc;
};
Crc32.prototype.get = function get() {
return ~this.crc;
};
Crc32.prototype.table = (function() {
var i, j, t, table = []; // Uint32Array is actually slower than []
for (i = 0; i < 256; i++) {
t = i;
for (j = 0; j < 8; j++)
if (t & 1)
t = (t >>> 1) ^ 0xEDB88320;
else
t = t >>> 1;
table[i] = t;
}
return table;
})();
// "no-op" codec
function NOOP() {}
global.NOOP = NOOP;
NOOP.prototype.append = function append(bytes, onprogress) {
return bytes;
};
NOOP.prototype.flush = function flush() {};
})(this);

966
sync/vendor/zipjs/zip.js vendored Executable file
View File

@ -0,0 +1,966 @@
/*
Copyright (c) 2013 Gildas Lormeau. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function(obj) {
"use strict";
var ERR_BAD_FORMAT = "File format is not recognized.";
var ERR_CRC = "CRC failed.";
var ERR_ENCRYPTED = "File contains encrypted entry.";
var ERR_ZIP64 = "File is using Zip64 (4gb+ file size).";
var ERR_READ = "Error while reading zip file.";
var ERR_WRITE = "Error while writing zip file.";
var ERR_WRITE_DATA = "Error while writing file data.";
var ERR_READ_DATA = "Error while reading file data.";
var ERR_DUPLICATED_NAME = "File already exists.";
var CHUNK_SIZE = 512 * 1024;
var TEXT_PLAIN = "text/plain";
var appendABViewSupported;
try {
appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0;
} catch (e) {
}
function Crc32() {
this.crc = -1;
}
Crc32.prototype.append = function append(data) {
var crc = this.crc | 0, table = this.table;
for (var offset = 0, len = data.length | 0; offset < len; offset++)
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
this.crc = crc;
};
Crc32.prototype.get = function get() {
return ~this.crc;
};
Crc32.prototype.table = (function() {
var i, j, t, table = []; // Uint32Array is actually slower than []
for (i = 0; i < 256; i++) {
t = i;
for (j = 0; j < 8; j++)
if (t & 1)
t = (t >>> 1) ^ 0xEDB88320;
else
t = t >>> 1;
table[i] = t;
}
return table;
})();
// "no-op" codec
function NOOP() {}
NOOP.prototype.append = function append(bytes, onprogress) {
return bytes;
};
NOOP.prototype.flush = function flush() {};
function blobSlice(blob, index, length) {
if (index < 0 || length < 0 || index + length > blob.size)
throw new RangeError('offset:' + index + ', length:' + length + ', size:' + blob.size);
if (blob.slice)
return blob.slice(index, index + length);
else if (blob.webkitSlice)
return blob.webkitSlice(index, index + length);
else if (blob.mozSlice)
return blob.mozSlice(index, index + length);
else if (blob.msSlice)
return blob.msSlice(index, index + length);
}
function getDataHelper(byteLength, bytes) {
var dataBuffer, dataArray;
dataBuffer = new ArrayBuffer(byteLength);
dataArray = new Uint8Array(dataBuffer);
if (bytes)
dataArray.set(bytes, 0);
return {
buffer : dataBuffer,
array : dataArray,
view : new DataView(dataBuffer)
};
}
// Readers
function Reader() {
}
function TextReader(text) {
var that = this, blobReader;
function init(callback, onerror) {
var blob = new Blob([ text ], {
type : TEXT_PLAIN
});
blobReader = new BlobReader(blob);
blobReader.init(function() {
that.size = blobReader.size;
callback();
}, onerror);
}
function readUint8Array(index, length, callback, onerror) {
blobReader.readUint8Array(index, length, callback, onerror);
}
that.size = 0;
that.init = init;
that.readUint8Array = readUint8Array;
}
TextReader.prototype = new Reader();
TextReader.prototype.constructor = TextReader;
function Data64URIReader(dataURI) {
var that = this, dataStart;
function init(callback) {
var dataEnd = dataURI.length;
while (dataURI.charAt(dataEnd - 1) == "=")
dataEnd--;
dataStart = dataURI.indexOf(",") + 1;
that.size = Math.floor((dataEnd - dataStart) * 0.75);
callback();
}
function readUint8Array(index, length, callback) {
var i, data = getDataHelper(length);
var start = Math.floor(index / 3) * 4;
var end = Math.ceil((index + length) / 3) * 4;
var bytes = obj.atob(dataURI.substring(start + dataStart, end + dataStart));
var delta = index - Math.floor(start / 4) * 3;
for (i = delta; i < delta + length; i++)
data.array[i - delta] = bytes.charCodeAt(i);
callback(data.array);
}
that.size = 0;
that.init = init;
that.readUint8Array = readUint8Array;
}
Data64URIReader.prototype = new Reader();
Data64URIReader.prototype.constructor = Data64URIReader;
function BlobReader(blob) {
var that = this;
function init(callback) {
that.size = blob.size;
callback();
}
function readUint8Array(index, length, callback, onerror) {
var reader = new FileReader();
reader.onload = function(e) {
callback(new Uint8Array(e.target.result));
};
reader.onerror = onerror;
try {
reader.readAsArrayBuffer(blobSlice(blob, index, length));
} catch (e) {
onerror(e);
}
}
that.size = 0;
that.init = init;
that.readUint8Array = readUint8Array;
}
BlobReader.prototype = new Reader();
BlobReader.prototype.constructor = BlobReader;
// Writers
function Writer() {
}
Writer.prototype.getData = function(callback) {
callback(this.data);
};
function TextWriter(encoding) {
var that = this, blob;
function init(callback) {
blob = new Blob([], {
type : TEXT_PLAIN
});
callback();
}
function writeUint8Array(array, callback) {
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
type : TEXT_PLAIN
});
callback();
}
function getData(callback, onerror) {
var reader = new FileReader();
reader.onload = function(e) {
callback(e.target.result);
};
reader.onerror = onerror;
reader.readAsText(blob, encoding);
}
that.init = init;
that.writeUint8Array = writeUint8Array;
that.getData = getData;
}
TextWriter.prototype = new Writer();
TextWriter.prototype.constructor = TextWriter;
function Data64URIWriter(contentType) {
var that = this, data = "", pending = "";
function init(callback) {
data += "data:" + (contentType || "") + ";base64,";
callback();
}
function writeUint8Array(array, callback) {
var i, delta = pending.length, dataString = pending;
pending = "";
for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++)
dataString += String.fromCharCode(array[i]);
for (; i < array.length; i++)
pending += String.fromCharCode(array[i]);
if (dataString.length > 2)
data += obj.btoa(dataString);
else
pending = dataString;
callback();
}
function getData(callback) {
callback(data + obj.btoa(pending));
}
that.init = init;
that.writeUint8Array = writeUint8Array;
that.getData = getData;
}
Data64URIWriter.prototype = new Writer();
Data64URIWriter.prototype.constructor = Data64URIWriter;
function BlobWriter(contentType) {
var blob, that = this;
function init(callback) {
blob = new Blob([], {
type : contentType
});
callback();
}
function writeUint8Array(array, callback) {
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
type : contentType
});
callback();
}
function getData(callback) {
callback(blob);
}
that.init = init;
that.writeUint8Array = writeUint8Array;
that.getData = getData;
}
BlobWriter.prototype = new Writer();
BlobWriter.prototype.constructor = BlobWriter;
/**
* inflate/deflate core functions
* @param worker {Worker} web worker for the task.
* @param initialMessage {Object} initial message to be sent to the worker. should contain
* sn(serial number for distinguishing multiple tasks sent to the worker), and codecClass.
* This function may add more properties before sending.
*/
function launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror) {
var chunkIndex = 0, index, outputSize, sn = initialMessage.sn, crc;
function onflush() {
worker.removeEventListener('message', onmessage, false);
onend(outputSize, crc);
}
function onmessage(event) {
var message = event.data, data = message.data, err = message.error;
if (err) {
err.toString = function () { return 'Error: ' + this.message; };
onreaderror(err);
return;
}
if (message.sn !== sn)
return;
if (typeof message.codecTime === 'number')
worker.codecTime += message.codecTime; // should be before onflush()
if (typeof message.crcTime === 'number')
worker.crcTime += message.crcTime;
switch (message.type) {
case 'append':
if (data) {
outputSize += data.length;
writer.writeUint8Array(data, function() {
step();
}, onwriteerror);
} else
step();
break;
case 'flush':
crc = message.crc;
if (data) {
outputSize += data.length;
writer.writeUint8Array(data, function() {
onflush();
}, onwriteerror);
} else
onflush();
break;
case 'progress':
if (onprogress)
onprogress(index + message.loaded, size);
break;
case 'importScripts': //no need to handle here
case 'newTask':
case 'echo':
break;
default:
console.warn('zip.js:launchWorkerProcess: unknown message: ', message);
}
}
function step() {
index = chunkIndex * CHUNK_SIZE;
// use `<=` instead of `<`, because `size` may be 0.
if (index <= size) {
reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
if (onprogress)
onprogress(index, size);
var msg = index === 0 ? initialMessage : {sn : sn};
msg.type = 'append';
msg.data = array;
// posting a message with transferables will fail on IE10
try {
worker.postMessage(msg, [array.buffer]);
} catch(ex) {
worker.postMessage(msg); // retry without transferables
}
chunkIndex++;
}, onreaderror);
} else {
worker.postMessage({
sn: sn,
type: 'flush'
});
}
}
outputSize = 0;
worker.addEventListener('message', onmessage, false);
step();
}
function launchProcess(process, reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror) {
var chunkIndex = 0, index, outputSize = 0,
crcInput = crcType === 'input',
crcOutput = crcType === 'output',
crc = new Crc32();
function step() {
var outputData;
index = chunkIndex * CHUNK_SIZE;
if (index < size)
reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(inputData) {
var outputData;
try {
outputData = process.append(inputData, function(loaded) {
if (onprogress)
onprogress(index + loaded, size);
});
} catch (e) {
onreaderror(e);
return;
}
if (outputData) {
outputSize += outputData.length;
writer.writeUint8Array(outputData, function() {
chunkIndex++;
setTimeout(step, 1);
}, onwriteerror);
if (crcOutput)
crc.append(outputData);
} else {
chunkIndex++;
setTimeout(step, 1);
}
if (crcInput)
crc.append(inputData);
if (onprogress)
onprogress(index, size);
}, onreaderror);
else {
try {
outputData = process.flush();
} catch (e) {
onreaderror(e);
return;
}
if (outputData) {
if (crcOutput)
crc.append(outputData);
outputSize += outputData.length;
writer.writeUint8Array(outputData, function() {
onend(outputSize, crc.get());
}, onwriteerror);
} else
onend(outputSize, crc.get());
}
}
step();
}
function inflate(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
var crcType = computeCrc32 ? 'output' : 'none';
if (obj.zip.useWebWorkers) {
var initialMessage = {
sn: sn,
codecClass: 'Inflater',
crcType: crcType,
};
launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror);
} else
launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror);
}
function deflate(worker, sn, reader, writer, level, onend, onprogress, onreaderror, onwriteerror) {
var crcType = 'input';
if (obj.zip.useWebWorkers) {
var initialMessage = {
sn: sn,
options: {level: level},
codecClass: 'Deflater',
crcType: crcType,
};
launchWorkerProcess(worker, initialMessage, reader, writer, 0, reader.size, onprogress, onend, onreaderror, onwriteerror);
} else
launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, crcType, onprogress, onend, onreaderror, onwriteerror);
}
function copy(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
var crcType = 'input';
if (obj.zip.useWebWorkers && computeCrc32) {
var initialMessage = {
sn: sn,
codecClass: 'NOOP',
crcType: crcType,
};
launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror);
} else
launchProcess(new NOOP(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror);
}
// ZipReader
function decodeASCII(str) {
var i, out = "", charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB',
'\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9',
'\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1',
'\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6',
'\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3',
'\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE',
'\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE',
'\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7',
'\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ' ];
for (i = 0; i < str.length; i++) {
charCode = str.charCodeAt(i) & 0xFF;
if (charCode > 127)
out += extendedASCII[charCode - 128];
else
out += String.fromCharCode(charCode);
}
return out;
}
function decodeUTF8(string) {
return decodeURIComponent(escape(string));
}
function getString(bytes) {
var i, str = "";
for (i = 0; i < bytes.length; i++)
str += String.fromCharCode(bytes[i]);
return str;
}
function getDate(timeRaw) {
var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff;
try {
return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5,
(time & 0x001F) * 2, 0);
} catch (e) {
}
}
function readCommonHeader(entry, data, index, centralDirectory, onerror) {
entry.version = data.view.getUint16(index, true);
entry.bitFlag = data.view.getUint16(index + 2, true);
entry.compressionMethod = data.view.getUint16(index + 4, true);
entry.lastModDateRaw = data.view.getUint32(index + 6, true);
entry.lastModDate = getDate(entry.lastModDateRaw);
if ((entry.bitFlag & 0x01) === 0x01) {
onerror(ERR_ENCRYPTED);
return;
}
if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) {
entry.crc32 = data.view.getUint32(index + 10, true);
entry.compressedSize = data.view.getUint32(index + 14, true);
entry.uncompressedSize = data.view.getUint32(index + 18, true);
}
if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) {
onerror(ERR_ZIP64);
return;
}
entry.filenameLength = data.view.getUint16(index + 22, true);
entry.extraFieldLength = data.view.getUint16(index + 24, true);
}
function createZipReader(reader, callback, onerror) {
var inflateSN = 0;
function Entry() {
}
Entry.prototype.getData = function(writer, onend, onprogress, checkCrc32) {
var that = this;
function testCrc32(crc32) {
var dataCrc32 = getDataHelper(4);
dataCrc32.view.setUint32(0, crc32);
return that.crc32 == dataCrc32.view.getUint32(0);
}
function getWriterData(uncompressedSize, crc32) {
if (checkCrc32 && !testCrc32(crc32))
onerror(ERR_CRC);
else
writer.getData(function(data) {
onend(data);
});
}
function onreaderror(err) {
onerror(err || ERR_READ_DATA);
}
function onwriteerror(err) {
onerror(err || ERR_WRITE_DATA);
}
reader.readUint8Array(that.offset, 30, function(bytes) {
var data = getDataHelper(bytes.length, bytes), dataOffset;
if (data.view.getUint32(0) != 0x504b0304) {
onerror(ERR_BAD_FORMAT);
return;
}
readCommonHeader(that, data, 4, false, onerror);
dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength;
writer.init(function() {
if (that.compressionMethod === 0)
copy(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
else
inflate(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
}, onwriteerror);
}, onreaderror);
};
function seekEOCDR(eocdrCallback) {
// "End of central directory record" is the last part of a zip archive, and is at least 22 bytes long.
// Zip file comment is the last part of EOCDR and has max length of 64KB,
// so we only have to search the last 64K + 22 bytes of a archive for EOCDR signature (0x06054b50).
var EOCDR_MIN = 22;
if (reader.size < EOCDR_MIN) {
onerror(ERR_BAD_FORMAT);
return;
}
var ZIP_COMMENT_MAX = 256 * 256, EOCDR_MAX = EOCDR_MIN + ZIP_COMMENT_MAX;
// In most cases, the EOCDR is EOCDR_MIN bytes long
doSeek(EOCDR_MIN, function() {
// If not found, try within EOCDR_MAX bytes
doSeek(Math.min(EOCDR_MAX, reader.size), function() {
onerror(ERR_BAD_FORMAT);
});
});
// seek last length bytes of file for EOCDR
function doSeek(length, eocdrNotFoundCallback) {
reader.readUint8Array(reader.size - length, length, function(bytes) {
for (var i = bytes.length - EOCDR_MIN; i >= 0; i--) {
if (bytes[i] === 0x50 && bytes[i + 1] === 0x4b && bytes[i + 2] === 0x05 && bytes[i + 3] === 0x06) {
eocdrCallback(new DataView(bytes.buffer, i, EOCDR_MIN));
return;
}
}
eocdrNotFoundCallback();
}, function() {
onerror(ERR_READ);
});
}
}
var zipReader = {
getEntries : function(callback) {
var worker = this._worker;
// look for End of central directory record
seekEOCDR(function(dataView) {
var datalength, fileslength;
datalength = dataView.getUint32(16, true);
fileslength = dataView.getUint16(8, true);
if (datalength < 0 || datalength >= reader.size) {
onerror(ERR_BAD_FORMAT);
return;
}
reader.readUint8Array(datalength, reader.size - datalength, function(bytes) {
var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes);
for (i = 0; i < fileslength; i++) {
entry = new Entry();
entry._worker = worker;
if (data.view.getUint32(index) != 0x504b0102) {
onerror(ERR_BAD_FORMAT);
return;
}
readCommonHeader(entry, data, index + 6, true, onerror);
entry.commentLength = data.view.getUint16(index + 32, true);
entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10);
entry.offset = data.view.getUint32(index + 42, true);
filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength));
entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename);
if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/")
entry.directory = true;
comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46
+ entry.filenameLength + entry.extraFieldLength + entry.commentLength));
entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment);
entries.push(entry);
index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength;
}
callback(entries);
}, function() {
onerror(ERR_READ);
});
});
},
close : function(callback) {
if (this._worker) {
this._worker.terminate();
this._worker = null;
}
if (callback)
callback();
},
_worker: null
};
if (!obj.zip.useWebWorkers)
callback(zipReader);
else {
createWorker('inflater',
function(worker) {
zipReader._worker = worker;
callback(zipReader);
},
function(err) {
onerror(err);
}
);
}
}
// ZipWriter
function encodeUTF8(string) {
return unescape(encodeURIComponent(string));
}
function getBytes(str) {
var i, array = [];
for (i = 0; i < str.length; i++)
array.push(str.charCodeAt(i));
return array;
}
function createZipWriter(writer, callback, onerror, dontDeflate) {
var files = {}, filenames = [], datalength = 0;
var deflateSN = 0;
function onwriteerror(err) {
onerror(err || ERR_WRITE);
}
function onreaderror(err) {
onerror(err || ERR_READ_DATA);
}
var zipWriter = {
add : function(name, reader, onend, onprogress, options) {
var header, filename, date;
var worker = this._worker;
function writeHeader(callback) {
var data;
date = options.lastModDate || new Date();
header = getDataHelper(26);
files[name] = {
headerArray : header.array,
directory : options.directory,
filename : filename,
offset : datalength,
comment : getBytes(encodeUTF8(options.comment || ""))
};
header.view.setUint32(0, 0x14000808);
if (options.version)
header.view.setUint8(0, options.version);
if (!dontDeflate && options.level !== 0 && !options.directory)
header.view.setUint16(4, 0x0800);
header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true);
header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true);
header.view.setUint16(22, filename.length, true);
data = getDataHelper(30 + filename.length);
data.view.setUint32(0, 0x504b0304);
data.array.set(header.array, 4);
data.array.set(filename, 30);
datalength += data.array.length;
writer.writeUint8Array(data.array, callback, onwriteerror);
}
function writeFooter(compressedLength, crc32) {
var footer = getDataHelper(16);
datalength += compressedLength || 0;
footer.view.setUint32(0, 0x504b0708);
if (typeof crc32 != "undefined") {
header.view.setUint32(10, crc32, true);
footer.view.setUint32(4, crc32, true);
}
if (reader) {
footer.view.setUint32(8, compressedLength, true);
header.view.setUint32(14, compressedLength, true);
footer.view.setUint32(12, reader.size, true);
header.view.setUint32(18, reader.size, true);
}
writer.writeUint8Array(footer.array, function() {
datalength += 16;
onend();
}, onwriteerror);
}
function writeFile() {
options = options || {};
name = name.trim();
if (options.directory && name.charAt(name.length - 1) != "/")
name += "/";
if (files.hasOwnProperty(name)) {
onerror(ERR_DUPLICATED_NAME);
return;
}
filename = getBytes(encodeUTF8(name));
filenames.push(name);
writeHeader(function() {
if (reader)
if (dontDeflate || options.level === 0)
copy(worker, deflateSN++, reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror);
else
deflate(worker, deflateSN++, reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror);
else
writeFooter();
}, onwriteerror);
}
if (reader)
reader.init(writeFile, onreaderror);
else
writeFile();
},
close : function(callback) {
if (this._worker) {
this._worker.terminate();
this._worker = null;
}
var data, length = 0, index = 0, indexFilename, file;
for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
file = files[filenames[indexFilename]];
length += 46 + file.filename.length + file.comment.length;
}
data = getDataHelper(length + 22);
for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
file = files[filenames[indexFilename]];
data.view.setUint32(index, 0x504b0102);
data.view.setUint16(index + 4, 0x1400);
data.array.set(file.headerArray, index + 6);
data.view.setUint16(index + 32, file.comment.length, true);
if (file.directory)
data.view.setUint8(index + 38, 0x10);
data.view.setUint32(index + 42, file.offset, true);
data.array.set(file.filename, index + 46);
data.array.set(file.comment, index + 46 + file.filename.length);
index += 46 + file.filename.length + file.comment.length;
}
data.view.setUint32(index, 0x504b0506);
data.view.setUint16(index + 8, filenames.length, true);
data.view.setUint16(index + 10, filenames.length, true);
data.view.setUint32(index + 12, length, true);
data.view.setUint32(index + 16, datalength, true);
writer.writeUint8Array(data.array, function() {
writer.getData(callback);
}, onwriteerror);
},
_worker: null
};
if (!obj.zip.useWebWorkers)
callback(zipWriter);
else {
createWorker('deflater',
function(worker) {
zipWriter._worker = worker;
callback(zipWriter);
},
function(err) {
onerror(err);
}
);
}
}
function resolveURLs(urls) {
var a = document.createElement('a');
return urls.map(function(url) {
a.href = url;
return a.href;
});
}
var DEFAULT_WORKER_SCRIPTS = {
deflater: ['z-worker.js', 'deflate.js'],
inflater: ['z-worker.js', 'inflate.js']
};
function createWorker(type, callback, onerror) {
if (obj.zip.workerScripts !== null && obj.zip.workerScriptsPath !== null) {
onerror(new Error('Either zip.workerScripts or zip.workerScriptsPath may be set, not both.'));
return;
}
var scripts;
if (obj.zip.workerScripts) {
scripts = obj.zip.workerScripts[type];
if (!Array.isArray(scripts)) {
onerror(new Error('zip.workerScripts.' + type + ' is not an array!'));
return;
}
scripts = resolveURLs(scripts);
} else {
scripts = DEFAULT_WORKER_SCRIPTS[type].slice(0);
scripts[0] = (obj.zip.workerScriptsPath || '') + scripts[0];
}
var worker = new Worker(scripts[0]);
// record total consumed time by inflater/deflater/crc32 in this worker
worker.codecTime = worker.crcTime = 0;
worker.postMessage({ type: 'importScripts', scripts: scripts.slice(1) });
worker.addEventListener('message', onmessage);
function onmessage(ev) {
var msg = ev.data;
if (msg.error) {
worker.terminate(); // should before onerror(), because onerror() may throw.
onerror(msg.error);
return;
}
if (msg.type === 'importScripts') {
worker.removeEventListener('message', onmessage);
worker.removeEventListener('error', errorHandler);
callback(worker);
}
}
// catch entry script loading error and other unhandled errors
worker.addEventListener('error', errorHandler);
function errorHandler(err) {
worker.terminate();
onerror(err);
}
}
function onerror_default(error) {
console.error(error);
}
obj.zip = {
Reader : Reader,
Writer : Writer,
BlobReader : BlobReader,
Data64URIReader : Data64URIReader,
TextReader : TextReader,
BlobWriter : BlobWriter,
Data64URIWriter : Data64URIWriter,
TextWriter : TextWriter,
createReader : function(reader, callback, onerror) {
onerror = onerror || onerror_default;
reader.init(function() {
createZipReader(reader, callback, onerror);
}, onerror);
},
createWriter : function(writer, callback, onerror, dontDeflate) {
onerror = onerror || onerror_default;
dontDeflate = !!dontDeflate;
writer.init(function() {
createZipWriter(writer, callback, onerror, dontDeflate);
}, onerror);
},
useWebWorkers : true,
/**
* Directory containing the default worker scripts (z-worker.js, deflate.js, and inflate.js), relative to current base url.
* E.g.: zip.workerScripts = './';
*/
workerScriptsPath : null,
/**
* Advanced option to control which scripts are loaded in the Web worker. If this option is specified, then workerScriptsPath must not be set.
* workerScripts.deflater/workerScripts.inflater should be arrays of urls to scripts for deflater/inflater, respectively.
* Scripts in the array are executed in order, and the first one should be z-worker.js, which is used to start the worker.
* All urls are relative to current base url.
* E.g.:
* zip.workerScripts = {
* deflater: ['z-worker.js', 'deflate.js'],
* inflater: ['z-worker.js', 'inflate.js']
* };
*/
workerScripts : null,
};
})(this);

View File

@ -1,45 +0,0 @@
# Install transifex-ruby - https://rubygems.org/gems/transifex-ruby
#
# Create a file called pull_locales_login.rb.
# Contents should be:
#
# Transifex.configure do |config|
# config.username = 'transifex.username'
# config.password = 'transifex.password'
# end
#
# Update require_relative to point to this file.
require 'transifex'
require 'fileutils'
require_relative '../stylish-chrome-bin/pull_locales_login'
project_slug = 'stylish-for-chrome'
transifex = Transifex::Client.new
project = transifex.project(project_slug)
project.languages.each do |language|
code = language.language_code
puts "Getting locale #{code}"
dir_name = "../_locales/#{code}"
Dir.mkdir(dir_name) if !Dir.exist?(dir_name)
has_content = false
project.resources.each do |resource|
c = resource.translation(code).content
file_name = "#{dir_name}/#{resource.name}"
begin
completed = resource.stats(code).completed
rescue Transifex::NotFound
puts "#{code} not found."
next
end
has_content ||= completed != "0%"
puts "Writing resource #{file_name}, #{completed} complete."
File.open(file_name, 'w') { |file| file.write(c) }
end
if !has_content
puts "Locale #{code} has no content, deleting."
FileUtils.rm_rf(dir_name)
end
end

View File

@ -1,2 +0,0 @@
ruby pull_locales.rb
python pull_locales_postprocess.py

View File

@ -1,45 +0,0 @@
#! python2
import io, os, json, re
from collections import OrderedDict
with io.open('../_locales/en/messages.json', 'r', encoding='utf-8') as f:
items = json.load(f).items()
english = [(k, v['message']) for k, v in items if 'message' in v]
english_placeholders = [(k, v['placeholders']) for k,v in items
if 'placeholders' in v]
for locale_name in os.listdir('../_locales'):
if locale_name == 'en':
continue
if not re.match(r'^\w{2}(_\w{2,3})?$', locale_name):
print('Skipped %s: not a locale dir' % locale_name)
continue
loc_path = '../_locales/' + locale_name + '/messages.json'
with io.open(loc_path, 'r+', encoding='utf-8') as f:
loc = json.load(f, object_pairs_hook=OrderedDict)
deduplicated = 0
for msgId, message in english:
if msgId in loc and loc[msgId].get('message', '') == message:
del loc[msgId]
deduplicated += 1
changed = 0
for msgId, placeholder in english_placeholders:
if msgId in loc and cmp(placeholder, loc[msgId].get('placeholders', None)) != 0:
loc[msgId]['placeholders'] = placeholder
changed += 1
if deduplicated > 0 or changed > 0:
f.seek(0)
json_str = json.dumps(loc, indent=1, ensure_ascii=False,
separators=(',', ': '), encoding='utf-8')
json_tabs = re.sub(r'^\s+', lambda s: s.group(0).replace(' ', '\t'),
json_str, flags=re.MULTILINE)
f.write(json_tabs)
f.truncate()
print('%s: %d deduplicated%s' % (
locale_name,
deduplicated,
', %d placeholder(s) added' % changed if changed else ''
))