Merge branch 'master' of https://github.com/openstyles/stylus
This commit is contained in:
commit
4c5b858f08
|
@ -16,7 +16,7 @@
|
|||
"description": "RegExp test report: title of the report"
|
||||
},
|
||||
"bckpInstStyles": {
|
||||
"message": "Styles Exportieren",
|
||||
"message": "Styles exportieren",
|
||||
"description": ""
|
||||
},
|
||||
"manageOnlyUsercss": {
|
||||
|
@ -36,7 +36,7 @@
|
|||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"installButton": {
|
||||
"message": "Installieren",
|
||||
"message": "Style installieren",
|
||||
"description": "Label for install button"
|
||||
},
|
||||
"styleMetaErrorCheckbox": {
|
||||
|
@ -47,6 +47,10 @@
|
|||
"message": "Ungültiges JSON Format",
|
||||
"description": "Setting linter config with invalid JSON"
|
||||
},
|
||||
"popupHotkeysTooltip": {
|
||||
"message": "Klicke, um Tastenkürzel zu sehen",
|
||||
"description": "Tooltip displayed when hovering the right edge of the extension popup"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Hintergrundfarbe",
|
||||
"description": ""
|
||||
|
@ -204,7 +208,7 @@
|
|||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"retrieveBckp": {
|
||||
"message": "Styles Importieren",
|
||||
"message": "Styles importieren",
|
||||
"description": ""
|
||||
},
|
||||
"confirmStop": {
|
||||
|
@ -322,6 +326,10 @@
|
|||
"message": "Zählung der aktiven Styles anzeigen ",
|
||||
"description": "Label (must be very short) for the checkbox in the toolbar button context menu controlling toolbar badge text."
|
||||
},
|
||||
"popupHotkeysInfo": {
|
||||
"message": "<1>-<9>, <0>, auch auf NumPad - schaltet n-ten Style um (0 ist 10)\n<A>-<Z> schaltet ersten Style, dessen Name mit diesem Buchstaben beginnt\n<Shift> öffnet Editor statt umzuschalten\n<Numpad +> aktiviert die aufgeführten Styles\n<Numpad –> deaktiviert die aufgeführten Styles\n<Numpad *> und <`> (backtick) - schaltet anfänglich aktivierte Styles; trifft nicht auf Styles zu, die erst aktiviert werden, wenn das Popup noch geöffnet ist. Dadurch kann die Anfangseinstellung nach einem Test wiederhergestellt werden: Einfach alle deaktivieren, dann schalte z.B. <Numpad –> <Numpad *>\nMehr dazu im Wiki",
|
||||
"description": "NOTE1: preserve < and > symbols so that <hotkey> is styled as a key.\nNOTE2: the last line is displayed as a text of the link to the wiki page.\nNOTE3: this is the list of hotkeys displayed after clicking the right edge of the extension popup."
|
||||
},
|
||||
"cm_lineWrapping": {
|
||||
"message": "Automatischer Zeilenumbruch",
|
||||
"description": "Label for the checkbox controlling word wrap option for the style editor."
|
||||
|
@ -413,7 +421,7 @@
|
|||
"description": "Text after the number of styles skipped due to being invalid (not a Stylus/Stylish backup file probably) in the report shown after importing styles"
|
||||
},
|
||||
"optionsAdvancedNewStyleAsUsercss": {
|
||||
"message": "Schreibe neuen Style als usercss",
|
||||
"message": "Schreibe neuen Style als Usercss",
|
||||
"description": ""
|
||||
},
|
||||
"genericResetLabel": {
|
||||
|
@ -525,6 +533,10 @@
|
|||
"message": "Optionen",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"usercssConfigIncomplete": {
|
||||
"message": "Der Style wurde aktualisiert oder gelöscht, nachdem der Einstellungsdialog gezeigt wurde. Folgende Variablen wurden nicht gespeichert, um Metadatenkorruption zu verhindern:",
|
||||
"description": ""
|
||||
},
|
||||
"openManage": {
|
||||
"message": "Verwalten",
|
||||
"description": "Link to open the manage page."
|
||||
|
@ -546,6 +558,10 @@
|
|||
"message": "Update installieren",
|
||||
"description": "Label for the button to install an update for a single style"
|
||||
},
|
||||
"syncStorageErrorSaving": {
|
||||
"message": "Der Wert kann nicht gespeichert werden. Versuche, die Textmenge zu reduzieren.",
|
||||
"description": "Displayed when trying to save an excessively big value via storage.sync API"
|
||||
},
|
||||
"optionsCheckUpdate": {
|
||||
"message": "Alle verfügbaren Updates Installieren",
|
||||
"description": ""
|
||||
|
@ -832,6 +848,10 @@
|
|||
"message": "Nichts wurde geändert.",
|
||||
"description": "Message in the report shown after importing styles"
|
||||
},
|
||||
"confirmDiscardChanges": {
|
||||
"message": "Änderungen verwerfen?",
|
||||
"description": "Generic label or title displayed when trying to close something (not a style) with unsaved changes"
|
||||
},
|
||||
"optionsActions": {
|
||||
"message": "Aktionen",
|
||||
"description": ""
|
||||
|
@ -886,7 +906,7 @@
|
|||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"installButtonReinstall": {
|
||||
"message": "Neuinstallieren",
|
||||
"message": "Style neu installieren",
|
||||
"description": "Label for reinstall button"
|
||||
},
|
||||
"linterInvalidConfigError": {
|
||||
|
@ -914,6 +934,10 @@
|
|||
"message": "Rückgängig",
|
||||
"description": "Button label"
|
||||
},
|
||||
"usercssReplaceTemplateConfirmation": {
|
||||
"message": "Ersetze das vorgegebene Template für neue Usercss styles mit dem vorliegenden Code?",
|
||||
"description": ""
|
||||
},
|
||||
"cm_keyMap": {
|
||||
"message": "Tastaturbelegung",
|
||||
"description": "Label for the drop-down list controlling the keymap for the style editor."
|
||||
|
@ -971,6 +995,10 @@
|
|||
"message": "Ermögliche Iframes via HTML[stylus-iframe]",
|
||||
"description": ""
|
||||
},
|
||||
"usercssEditorNamePlaceholder": {
|
||||
"message": "Gib @name im Code an",
|
||||
"description": "Placeholder text for the empty name input field when creating a new Usercss style"
|
||||
},
|
||||
"addStyleLabel": {
|
||||
"message": "Neuen Style erstellen",
|
||||
"description": "Label for the button to go to the add style page"
|
||||
|
@ -980,7 +1008,7 @@
|
|||
"description": ""
|
||||
},
|
||||
"installButtonUpdate": {
|
||||
"message": "Aktualisieren",
|
||||
"message": "Style updaten",
|
||||
"description": "Label for update button"
|
||||
},
|
||||
"backupButtons": {
|
||||
|
@ -996,7 +1024,7 @@
|
|||
"description": "Label for the button to go to the edit style page"
|
||||
},
|
||||
"installButtonInstalled": {
|
||||
"message": "Installiert",
|
||||
"message": "Style installiert",
|
||||
"description": "Text displayed when the style is successfully installed"
|
||||
},
|
||||
"author": {
|
||||
|
@ -1034,5 +1062,9 @@
|
|||
"confirmClose": {
|
||||
"message": "Schließen",
|
||||
"description": "'Close' button in a confirm dialog"
|
||||
},
|
||||
"usercssReplaceTemplateName": {
|
||||
"message": "Ein leeres @name ersetzt das vorgegebene Template",
|
||||
"description": "The text shown after @name when creating a new Usercss style"
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@
|
|||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"installButton": {
|
||||
"message": "Instalar",
|
||||
"message": "Instalar estilo",
|
||||
"description": "Label for install button"
|
||||
},
|
||||
"styleMetaErrorCheckbox": {
|
||||
|
@ -47,6 +47,10 @@
|
|||
"message": "Formato JSON no válido",
|
||||
"description": "Setting linter config with invalid JSON"
|
||||
},
|
||||
"popupHotkeysTooltip": {
|
||||
"message": "Pulse para ver teclas de atajo disponibles.",
|
||||
"description": "Tooltip displayed when hovering the right edge of the extension popup"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Color de fondo",
|
||||
"description": ""
|
||||
|
@ -330,6 +334,10 @@
|
|||
"message": "Mostrar número de estilos activos",
|
||||
"description": "Label (must be very short) for the checkbox in the toolbar button context menu controlling toolbar badge text."
|
||||
},
|
||||
"popupHotkeysInfo": {
|
||||
"message": "<1>-<9>, <0>, también en el teclado numérico - acciona el n-esimo estilo (0 es 10)\n<A>-<Z> acciona el primer estilo con un nombre que comienza con la letra\n<Shift> abre el editor en lugar de accionar\n<Numpad +> habilita los estilos listados\n<Numpad –> deshabilita los estilos listados\n<Numpad *> y <`> (acento grave) - acciona los estilos habilitados inicialmente; no se aplica a los estilos habilitados subsecuentemente mientras el cuadro emergente está abierto, así que puede restaurar la selección inicial tras probar el material: simplemente deshabilite todo, y luego accione, es decir <Numpad –> <Numpad *>\nMás información en el wiki",
|
||||
"description": "NOTE1: preserve < and > symbols so that <hotkey> is styled as a key.\nNOTE2: the last line is displayed as a text of the link to the wiki page.\nNOTE3: this is the list of hotkeys displayed after clicking the right edge of the extension popup."
|
||||
},
|
||||
"cm_lineWrapping": {
|
||||
"message": "Ajuste de línea",
|
||||
"description": "Label for the checkbox controlling word wrap option for the style editor."
|
||||
|
@ -541,6 +549,10 @@
|
|||
"message": "Opciones",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"usercssConfigIncomplete": {
|
||||
"message": "El estilo se actualizó o borró después de que se mostrara el cuadro de diálogo de configuración. Estas variables no se guardaron para evitar corromper los metadatos del estilo:",
|
||||
"description": ""
|
||||
},
|
||||
"openManage": {
|
||||
"message": "Administrar",
|
||||
"description": "Link to open the manage page."
|
||||
|
@ -562,6 +574,10 @@
|
|||
"message": "Instalar actualización",
|
||||
"description": "Label for the button to install an update for a single style"
|
||||
},
|
||||
"syncStorageErrorSaving": {
|
||||
"message": "El valor no se puede guardar. Trate de reducir la longitud del texto.",
|
||||
"description": "Displayed when trying to save an excessively big value via storage.sync API"
|
||||
},
|
||||
"optionsCheckUpdate": {
|
||||
"message": "Buscar e instalar todas las actualizaciones disponibles",
|
||||
"description": ""
|
||||
|
@ -864,6 +880,10 @@
|
|||
"message": "No se cambió nada.",
|
||||
"description": "Message in the report shown after importing styles"
|
||||
},
|
||||
"confirmDiscardChanges": {
|
||||
"message": "¿Descartar los cambios?",
|
||||
"description": "Generic label or title displayed when trying to close something (not a style) with unsaved changes"
|
||||
},
|
||||
"optionsActions": {
|
||||
"message": "Acciones",
|
||||
"description": ""
|
||||
|
@ -918,7 +938,7 @@
|
|||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"installButtonReinstall": {
|
||||
"message": "Reinstalar",
|
||||
"message": "Reinstalar estilo",
|
||||
"description": "Label for reinstall button"
|
||||
},
|
||||
"linterInvalidConfigError": {
|
||||
|
@ -942,6 +962,10 @@
|
|||
"message": "Deshacer",
|
||||
"description": "Button label"
|
||||
},
|
||||
"usercssReplaceTemplateConfirmation": {
|
||||
"message": "¿Reemplazar con el código actual la plantilla predeterminada para nuevos estilos Usercss?",
|
||||
"description": ""
|
||||
},
|
||||
"cm_keyMap": {
|
||||
"message": "Mapa de teclado",
|
||||
"description": "Label for the drop-down list controlling the keymap for the style editor."
|
||||
|
@ -999,6 +1023,10 @@
|
|||
"message": "Exponer marcos integrados (iframes) vía HTML[stylus-iframe]",
|
||||
"description": ""
|
||||
},
|
||||
"usercssEditorNamePlaceholder": {
|
||||
"message": "Especifique @name en el código",
|
||||
"description": "Placeholder text for the empty name input field when creating a new Usercss style"
|
||||
},
|
||||
"addStyleLabel": {
|
||||
"message": "Escribir un estilo nuevo",
|
||||
"description": "Label for the button to go to the add style page"
|
||||
|
@ -1008,7 +1036,7 @@
|
|||
"description": ""
|
||||
},
|
||||
"installButtonUpdate": {
|
||||
"message": "Actualizar",
|
||||
"message": "Actualizar estilo",
|
||||
"description": "Label for update button"
|
||||
},
|
||||
"backupButtons": {
|
||||
|
@ -1024,7 +1052,7 @@
|
|||
"description": "Label for the button to go to the edit style page"
|
||||
},
|
||||
"installButtonInstalled": {
|
||||
"message": "Instalado",
|
||||
"message": "Estilo instalado",
|
||||
"description": "Text displayed when the style is successfully installed"
|
||||
},
|
||||
"author": {
|
||||
|
@ -1066,5 +1094,9 @@
|
|||
"confirmClose": {
|
||||
"message": "Cerrar",
|
||||
"description": "'Close' button in a confirm dialog"
|
||||
},
|
||||
"usercssReplaceTemplateName": {
|
||||
"message": "@name vacío reemplaza la plantilla predeterminada",
|
||||
"description": "The text shown after @name when creating a new Usercss style"
|
||||
}
|
||||
}
|
|
@ -19,6 +19,10 @@
|
|||
"message": "Ekspordi stiilid",
|
||||
"description": ""
|
||||
},
|
||||
"manageOnlyUsercss": {
|
||||
"message": "Ainult Usercss stiilid",
|
||||
"description": "Checkbox to show only Usercss styles"
|
||||
},
|
||||
"optionsUpdateInterval": {
|
||||
"message": "Automaatselt kontrolli ja installi kõik saadaolevad kasutajastiili uuendused (tundides)",
|
||||
"description": ""
|
||||
|
@ -83,6 +87,10 @@
|
|||
"message": "Stiili ei rakendatud selle \"regexp()\" vale kasutuse tõttu",
|
||||
"description": "Tooltip in the popup for styles that were not applied at all"
|
||||
},
|
||||
"colorpickerSwitchFormatTooltip": {
|
||||
"message": "Vaheta formaate: HEX -> RGB -> HSL.\nShift-klõps vastupidise suuna jaoks.\nSamuti klahvidega PgUp (PageUp), PgDn (PageDown).",
|
||||
"description": "Tooltip for the switch button in the color picker popup in the style editor."
|
||||
},
|
||||
"styleRegexpInvalidExplanation": {
|
||||
"message": "Teatud \"regexp()\" reegleid ei suudetud üldse kompileerida.",
|
||||
"description": ""
|
||||
|
@ -195,6 +203,10 @@
|
|||
"message": "Tühista",
|
||||
"description": ""
|
||||
},
|
||||
"cm_autoCloseBracketsTooltip": {
|
||||
"message": "Automaatselt lisab sulgeva paarilise, kui kirjutad avava ühest järgnevast: ()[]{}''\"\"",
|
||||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"retrieveBckp": {
|
||||
"message": "Impordi stiilid",
|
||||
"description": ""
|
||||
|
@ -252,6 +264,15 @@
|
|||
"message": "Ainult kohalikult loodud stiilid",
|
||||
"description": "Checkbox to show only locally created styles i.e. non-updatable"
|
||||
},
|
||||
"styleMetaErrorPreprocessor": {
|
||||
"message": "Mittetoetatud eeltöötleja: $preprocessor$",
|
||||
"description": "Error displayed when the value of @preprocessor is not supported",
|
||||
"placeholders": {
|
||||
"preprocessor": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"linterIssuesHelp": {
|
||||
"message": "$link$ leidis need vead:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
|
@ -277,6 +298,10 @@
|
|||
"message": "Kontrolli uuesti, ma ei muutnud ühtegi stiili!",
|
||||
"description": "Label for the button to apply all detected updates"
|
||||
},
|
||||
"manageOnlyNonUsercss": {
|
||||
"message": "Ainult mitte-Usercss stiilid",
|
||||
"description": "Checkbox to show only non-Usercss (standard) styles"
|
||||
},
|
||||
"liveReloadLabel": {
|
||||
"message": "Reaalajas uuestilaadimine",
|
||||
"description": "The label of live-reload feature"
|
||||
|
@ -512,6 +537,10 @@
|
|||
"message": "Valikud",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"usercssConfigIncomplete": {
|
||||
"message": "Stiili uuendati või eemaldati pärast seadistusdialoogi kuvamist. Neid muutujaid ei salvestatud, et vältida stiili metaandmete korrumpeerumist:",
|
||||
"description": ""
|
||||
},
|
||||
"openManage": {
|
||||
"message": "Halda",
|
||||
"description": "Link to open the manage page."
|
||||
|
@ -533,6 +562,10 @@
|
|||
"message": "Installi uuendus",
|
||||
"description": "Label for the button to install an update for a single style"
|
||||
},
|
||||
"syncStorageErrorSaving": {
|
||||
"message": "Väärtust ei saa salvestada. Proovi teksti hulka vähendada.",
|
||||
"description": "Displayed when trying to save an excessively big value via storage.sync API"
|
||||
},
|
||||
"optionsCheckUpdate": {
|
||||
"message": "Kontrolli ja installi kõik saadaolevad uuendused",
|
||||
"description": ""
|
||||
|
@ -653,7 +686,7 @@
|
|||
"description": "Text that displays when an update check skipped updating the style to avoid losing local modifications"
|
||||
},
|
||||
"linterRulesLink": {
|
||||
"message": "Vaata reeglite täielikku loendit",
|
||||
"message": "Vaata reeglite täielikku loendit lehel",
|
||||
"description": "Stylelint or CSSLint rules label added immediately before a link"
|
||||
},
|
||||
"styleUpdateDiscardChanges": {
|
||||
|
@ -717,6 +750,15 @@
|
|||
"message": "Automaattäide kirjutamisel",
|
||||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"linterCSSLintIncompatible": {
|
||||
"message": "CSSLint ei toeta eelprotsessorit $preprocessorname$",
|
||||
"description": "The label to display when the preprocessor isn't compatible with CSSLint",
|
||||
"placeholders": {
|
||||
"preprocessorname": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"styleMetaErrorSelectValueMismatch": {
|
||||
"message": "Vigane @select: väärtust pole loendis olemas",
|
||||
"description": "Error displayed when the value of @select is invalid"
|
||||
|
@ -826,6 +868,10 @@
|
|||
"message": "Midagi ei muudetud.",
|
||||
"description": "Message in the report shown after importing styles"
|
||||
},
|
||||
"confirmDiscardChanges": {
|
||||
"message": "Tühistada muudatused?",
|
||||
"description": "Generic label or title displayed when trying to close something (not a style) with unsaved changes"
|
||||
},
|
||||
"optionsActions": {
|
||||
"message": "Tegevused",
|
||||
"description": ""
|
||||
|
@ -867,6 +913,10 @@
|
|||
"message": "identset vahele jäetud",
|
||||
"description": "Text after the number of styles skipped due to being identical to the already installed ones in the report shown after importing styles"
|
||||
},
|
||||
"manageNewStyleAsUsercss": {
|
||||
"message": "Usercss-ina",
|
||||
"description": "VERY SHORT label for the checkbox next to the 'Write new style' button in the style manager"
|
||||
},
|
||||
"optionsPopupWidth": {
|
||||
"message": "Hüpikakna laius (pikslites)",
|
||||
"description": ""
|
||||
|
@ -887,6 +937,15 @@
|
|||
"message": "Ei",
|
||||
"description": "'No' button in a confirm dialog"
|
||||
},
|
||||
"styleMissingMeta": {
|
||||
"message": "$key$metaandmed puuduvad",
|
||||
"description": "Error displayed when a mandatory metadata is missing",
|
||||
"placeholders": {
|
||||
"key": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"appliesLineWidgetWarning": {
|
||||
"message": "Ei tööta minimeeritud CSS-iga",
|
||||
"description": "A warning that applies-to information won't show properly with minified CSS"
|
||||
|
@ -895,6 +954,10 @@
|
|||
"message": "Võta tagasi",
|
||||
"description": "Button label"
|
||||
},
|
||||
"usercssReplaceTemplateConfirmation": {
|
||||
"message": "Asendad vaikimisi malli uutes kasutajacss stiilides praeguse koodiga?",
|
||||
"description": ""
|
||||
},
|
||||
"cm_keyMap": {
|
||||
"message": "Klahvimäärangud",
|
||||
"description": "Label for the drop-down list controlling the keymap for the style editor."
|
||||
|
@ -927,6 +990,10 @@
|
|||
"message": "Asenda tekstiga",
|
||||
"description": "Label before the replace-with input field in the editor shown on Ctrl-H etc."
|
||||
},
|
||||
"liveReloadError": {
|
||||
"message": "Faili vaatamisel esines viga",
|
||||
"description": "The label of live-reload error"
|
||||
},
|
||||
"deleteStyleLabel": {
|
||||
"message": "Kustuta",
|
||||
"description": "Label for the button to delete a style"
|
||||
|
@ -948,6 +1015,10 @@
|
|||
"message": "Paljasta iframe-id HTML [stylus-iframe] kaudu",
|
||||
"description": ""
|
||||
},
|
||||
"usercssEditorNamePlaceholder": {
|
||||
"message": "Kirjelda koodis @name",
|
||||
"description": "Placeholder text for the empty name input field when creating a new Usercss style"
|
||||
},
|
||||
"addStyleLabel": {
|
||||
"message": "Kirjuta uus stiil",
|
||||
"description": "Label for the button to go to the add style page"
|
||||
|
@ -1015,5 +1086,9 @@
|
|||
"confirmClose": {
|
||||
"message": "Sulge",
|
||||
"description": "'Close' button in a confirm dialog"
|
||||
},
|
||||
"usercssReplaceTemplateName": {
|
||||
"message": "Tühi @name asendab vaikimisi malli",
|
||||
"description": "The text shown after @name when creating a new Usercss style"
|
||||
}
|
||||
}
|
|
@ -3,6 +3,10 @@
|
|||
"message": "Minden",
|
||||
"description": "Text displayed for styles that apply to all sites"
|
||||
},
|
||||
"linterIssues": {
|
||||
"message": "Problémák",
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"defaultTheme": {
|
||||
"message": "alapértelmezett",
|
||||
"description": "Default CodeMirror CSS theme option on the edit style page"
|
||||
|
@ -27,6 +31,14 @@
|
|||
"message": "Exportálás",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"styleMetaErrorCheckbox": {
|
||||
"message": "Érvénytelen @var jelölődoboz: az értéknek 0-nak vagy 1-nek kell lennie",
|
||||
"description": "Error displayed when the value of @var checkbox is invalid"
|
||||
},
|
||||
"linterJSONError": {
|
||||
"message": "Érvénytelen JSON formátum",
|
||||
"description": "Setting linter config with invalid JSON"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Háttérszín",
|
||||
"description": ""
|
||||
|
@ -111,6 +123,10 @@
|
|||
"message": "Szürke mód",
|
||||
"description": "Label for the checkbox that toggles grayed out mode of applies-to favicons in the new UI on manage page"
|
||||
},
|
||||
"versionInvalidOlder": {
|
||||
"message": "A verzió régebb a telepített stílusnál",
|
||||
"description": "Displayed when the version of style is older than the installed one"
|
||||
},
|
||||
"confirmYes": {
|
||||
"message": "Igen",
|
||||
"description": "'Yes' button in a confirm dialog"
|
||||
|
@ -135,6 +151,10 @@
|
|||
"message": "Engedélyezve",
|
||||
"description": "Label for the enabled state of styles"
|
||||
},
|
||||
"linterConfigTooltip": {
|
||||
"message": "Kattints ennek a linternek a beállításához",
|
||||
"description": "Icon tooltip to indicate that it opens a popup with the selected linter configuration"
|
||||
},
|
||||
"styleToMozillaFormatHelp": {
|
||||
"message": "A Mozilla formátumú kódot beküldheted a userstyles.org-ra és használhatod a klasszikus Stylish Firefoxkiegészítővel.",
|
||||
"description": "Help info for the Mozilla format header section that converts the code to/from Mozilla format"
|
||||
|
@ -151,6 +171,10 @@
|
|||
"message": "Mentés",
|
||||
"description": "Label for save button for style editing"
|
||||
},
|
||||
"genericSavedMessage": {
|
||||
"message": "Mentve",
|
||||
"description": "Used in various parts of the UI to indicate that something was saved"
|
||||
},
|
||||
"confirmDelete": {
|
||||
"message": "Törlés",
|
||||
"description": ""
|
||||
|
@ -216,6 +240,15 @@
|
|||
"message": "Csak helyileg létrehozott stílusok",
|
||||
"description": "Checkbox to show only locally created styles i.e. non-updatable"
|
||||
},
|
||||
"linterIssuesHelp": {
|
||||
"message": "$link$a következő hibákat találta:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"searchStyles": {
|
||||
"message": "Tartalom keresése",
|
||||
"description": "Label for the search filter textbox on the Manage styles page"
|
||||
|
@ -330,6 +363,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"dysfunctional": {
|
||||
"message": "A Stylus nem működhet privát ablakokon belül, mert a Firefox nem enged közvetlen kapcsolatot a kiegészítő belső háttéroldal-kontextusával.",
|
||||
"description": "Displayed in Firefox when its settings make Stylus dysfunctional"
|
||||
},
|
||||
"styleSectionsTitle": {
|
||||
"message": "Szekciók",
|
||||
"description": "Title for the style sections section"
|
||||
|
@ -338,6 +375,10 @@
|
|||
"message": "kihagyott érvénytelen",
|
||||
"description": "Text after the number of styles skipped due to being invalid (not a Stylus/Stylish backup file probably) in the report shown after importing styles"
|
||||
},
|
||||
"genericResetLabel": {
|
||||
"message": "VIsszaállítás",
|
||||
"description": "Used in various parts of UI to indicate that something may be reset to its original state"
|
||||
},
|
||||
"editStyleTitle": {
|
||||
"message": "A(z) $stylename$ stílus szerkesztése",
|
||||
"description": "Title of the page for editing styles",
|
||||
|
@ -363,6 +404,10 @@
|
|||
"message": "Használd a /re/ szintaxist a regexp kereséshez",
|
||||
"description": "Label after the search input field in the editor shown on Ctrl-F"
|
||||
},
|
||||
"popupBordersTooltip": {
|
||||
"message": "Hasznos az új Chromehoz létrehozott sötét témákhoz, mert nem színezi át az oldalszegélyeket",
|
||||
"description": ""
|
||||
},
|
||||
"updateCheckManualUpdateHint": {
|
||||
"message": "Egy frissítés erőltetése minden helyi szerkesztést felül fog írni.",
|
||||
"description": "Additional text displayed when an update check skipped updating the style to avoid losing local modifications"
|
||||
|
@ -484,6 +529,10 @@
|
|||
"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).",
|
||||
"description": ""
|
||||
},
|
||||
"linterCSSLintSettings": {
|
||||
"message": "(Szabály megadása: 0 = letiltva; 1 = figyelmeztetés; 2 = hiba)",
|
||||
"description": "CSSLint rule config values"
|
||||
},
|
||||
"styleBeautifyIndentConditional": {
|
||||
"message": "@media, @supports behúzása",
|
||||
"description": "CSS-beautifier option"
|
||||
|
@ -504,6 +553,10 @@
|
|||
"message": "Az összes stílus kikapcsolása",
|
||||
"description": "Label for the checkbox that turns all enabled styles off."
|
||||
},
|
||||
"appliesLineWidgetLabel": {
|
||||
"message": "Információ megjelenítése arról, hogy mire van alkalmazva",
|
||||
"description": "Label for the checkbox to display applies-to information in the single editor"
|
||||
},
|
||||
"updateCheckSkippedMaybeLocallyEdited": {
|
||||
"message": "Lehet, hogy ezt a stílust helyileg szerkesztették",
|
||||
"description": "Text that displays when an update check skipped updating the style to avoid losing possible local modifications"
|
||||
|
@ -520,6 +573,10 @@
|
|||
"message": "A frissítés befejeződött.",
|
||||
"description": "Text that displays when an update completed"
|
||||
},
|
||||
"dysfunctionalBackgroundConnection": {
|
||||
"message": "Nem mőködhet megfelelően egy ebben a verzióban található ismert hiba miatt: chrome.extension.getBackgroundPage() eredménye nem érvényes",
|
||||
"description": "Displayed in style manager when unable to connect to the background page"
|
||||
},
|
||||
"checkingForUpdate": {
|
||||
"message": "Ellenőrzés...",
|
||||
"description": "Text to display when checking a style for an update"
|
||||
|
@ -532,6 +589,10 @@
|
|||
"message": "Megjelenítendő célok száma",
|
||||
"description": "Label for the numeric input box to limit max number of applies-to targets in the new UI on manage page"
|
||||
},
|
||||
"popupManageTooltip": {
|
||||
"message": "Shift-kattintás vagy jobb kattintás megnyitja a stíluskezelőt a jelenlegi oldalra érvényesülő stílusokkal",
|
||||
"description": "Tooltip for the 'Manage' button in the popup."
|
||||
},
|
||||
"manageFaviconsHelp": {
|
||||
"message": "A Stylus egy külső szolgáltatást használ (https://www.google.com/s2/favicons)",
|
||||
"description": "Label for the checkbox that toggles applies-to favicons in the new UI on manage page"
|
||||
|
@ -540,6 +601,10 @@
|
|||
"message": "Ez a stílus helyileg lett szerkesztve.",
|
||||
"description": "Text that displays when an update check skipped updating the style to avoid losing local modifications"
|
||||
},
|
||||
"linterRulesLink": {
|
||||
"message": "Lista az összes stílusról",
|
||||
"description": "Stylelint or CSSLint rules label added immediately before a link"
|
||||
},
|
||||
"optionsResetButton": {
|
||||
"message": "Beállítások visszaállítása alapra",
|
||||
"description": ""
|
||||
|
@ -552,6 +617,15 @@
|
|||
"message": "Delete hozzáadása a gyorsmenühöz",
|
||||
"description": ""
|
||||
},
|
||||
"linterConfigPopupTitle": {
|
||||
"message": "$linter$ szabály beállítása",
|
||||
"description": "Stylelint or CSSLint popup header",
|
||||
"placeholders": {
|
||||
"linter": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"importReportLegendUpdatedBoth": {
|
||||
"message": "metainformáció és kód frissítve",
|
||||
"description": "Text after the number of styles updated entirely in the report shown after importing styles"
|
||||
|
@ -580,6 +654,19 @@
|
|||
"message": "Automatikus kiegészítés gépeléskor",
|
||||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"styleMetaErrorColor": {
|
||||
"message": "A(z) $color$ nem valódi szín",
|
||||
"description": "Error displayed when the value of @var color is invalid",
|
||||
"placeholders": {
|
||||
"color": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"externalFeedback": {
|
||||
"message": "Visszajelzés",
|
||||
"description": "Label for the external link to send feedback for the style"
|
||||
},
|
||||
"manageOnlyDisabled": {
|
||||
"message": "Csak letiltott stílusok",
|
||||
"description": "Checkbox to show only disabled styles"
|
||||
|
@ -608,10 +695,18 @@
|
|||
"message": "Stílus hozzáadása",
|
||||
"description": "Title of the page for adding styles"
|
||||
},
|
||||
"externalHomepage": {
|
||||
"message": "Kezdőoldal",
|
||||
"description": "Label for the external link to style's homepage"
|
||||
},
|
||||
"importReplaceLabel": {
|
||||
"message": "Stílus felülírása",
|
||||
"description": "Label for the button to import and overwrite current style"
|
||||
},
|
||||
"popupOpenEditInWindowTooltip": {
|
||||
"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.",
|
||||
"description": "Label for the checkbox controlling 'edit' action behavior in the popup."
|
||||
},
|
||||
"dbError": {
|
||||
"message": "Hiba történt a Stylus adatbázisának használatakor. Szeretnéd meglátogatni a lehetséges megoldásokat tartalmazó weboldalt?",
|
||||
"description": "Prompt when a DB error is encountered"
|
||||
|
@ -684,6 +779,10 @@
|
|||
"message": "Felugró ablak szélessége (pixelben)",
|
||||
"description": ""
|
||||
},
|
||||
"linterInvalidConfigError": {
|
||||
"message": "Nincs mentve ezek miatt az érvénytelen beállítások miatt:",
|
||||
"description": "Invalid linter config will show a message followed by a list of invalid entries"
|
||||
},
|
||||
"confirmNo": {
|
||||
"message": "Nem",
|
||||
"description": "'No' button in a confirm dialog"
|
||||
|
@ -696,6 +795,10 @@
|
|||
"message": "Billentyűműveletek",
|
||||
"description": "Label for the drop-down list controlling the keymap for the style editor."
|
||||
},
|
||||
"externalSupport": {
|
||||
"message": "Támogatás",
|
||||
"description": "Label for the external link to style's support site"
|
||||
},
|
||||
"manageNewUI": {
|
||||
"message": "Az új kezelési felületkiosztás",
|
||||
"description": "Label for the checkbox that toggles the new UI on manage page"
|
||||
|
@ -724,6 +827,15 @@
|
|||
"message": "Frissítés telepítése (a helyi módosítások felül lesznek írva)",
|
||||
"description": "Additional text displayed when an update check skipped updating the style to avoid losing local modifications"
|
||||
},
|
||||
"styleInstallFailed": {
|
||||
"message": "A stílus telepítése nem sikerült!\n$error$",
|
||||
"description": "Warning when installation failed",
|
||||
"placeholders": {
|
||||
"error": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsAdvancedExposeIframes": {
|
||||
"message": "iframe-ek kitevése HTML[stylus-iframe]-en keresztül",
|
||||
"description": ""
|
||||
|
@ -748,10 +860,18 @@
|
|||
"message": "Szerkesztés",
|
||||
"description": "Label for the button to go to the edit style page"
|
||||
},
|
||||
"installButtonInstalled": {
|
||||
"message": "Stílus telepítve",
|
||||
"description": "Text displayed when the style is successfully installed"
|
||||
},
|
||||
"cm_theme": {
|
||||
"message": "Téma",
|
||||
"description": "Label for the style editor's CSS theme."
|
||||
},
|
||||
"popupOpenEditInWindow": {
|
||||
"message": "Szerkesztő megnyitása új ablakban",
|
||||
"description": "Label for the checkbox controlling 'edit' action behavior in the popup."
|
||||
},
|
||||
"backupMessage": {
|
||||
"message": "Válassz ki egy fájlt vagy húzd erre az oldalra!",
|
||||
"description": "Message for backup"
|
||||
|
@ -764,6 +884,10 @@
|
|||
"message": "Írj be egy parancsot",
|
||||
"description": "Placeholder text of inputbox in keymap help popup on the edit style page. Must be very short"
|
||||
},
|
||||
"linterResetMessage": {
|
||||
"message": "Egy véletlen visszaállítás visszavonásához nyomj Ctrl-Z-t (vagy Cmd-Z) a szövegdobozon belül)",
|
||||
"description": "Reset button tooltip to inform user on how to undo an accidental reset"
|
||||
},
|
||||
"description": {
|
||||
"message": "Tervezd újra a webet a Stylus-szal, ami egy stíluskezelő. A Stylus lehetővé teszi a témák és egyéni külsők egyszerű telepítését sok népszerű oldalhoz.",
|
||||
"description": "Extension description"
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"message": "スタイルをエクスポート",
|
||||
"description": ""
|
||||
},
|
||||
"manageOnlyUsercss": {
|
||||
"message": "Usercssスタイルのみ",
|
||||
"description": "Checkbox to show only Usercss styles"
|
||||
},
|
||||
"optionsUpdateInterval": {
|
||||
"message": "利用可能なすべてのユーザースタイルの更新を自動的にチェックしてインストールします(時間単位)",
|
||||
"description": ""
|
||||
|
@ -43,6 +47,10 @@
|
|||
"message": "不正なJSONフォーマットです",
|
||||
"description": "Setting linter config with invalid JSON"
|
||||
},
|
||||
"popupHotkeysTooltip": {
|
||||
"message": "クリックすると有効なホットキーを表示します",
|
||||
"description": "Tooltip displayed when hovering the right edge of the extension popup"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "背景色",
|
||||
"description": ""
|
||||
|
@ -83,6 +91,10 @@
|
|||
"message": "'regexp()' の誤った使用のためスタイルを適用できませんでした",
|
||||
"description": "Tooltip in the popup for styles that were not applied at all"
|
||||
},
|
||||
"colorpickerSwitchFormatTooltip": {
|
||||
"message": "フォーマット切り替え: HEX -> RGB -> HSL\nシフト - クリック で逆向きに切り替えます。\nまた、PgUp (PageUp), PgDn (PageDown) キーも使用できます。",
|
||||
"description": "Tooltip for the switch button in the color picker popup in the style editor."
|
||||
},
|
||||
"styleRegexpInvalidExplanation": {
|
||||
"message": "いくつかの 'regexp()' のルールはコンパイルできませんでした",
|
||||
"description": ""
|
||||
|
@ -232,7 +244,7 @@
|
|||
"description": "Text after the number of styles with updated code (meta info is unchanged) in the report shown after importing styles"
|
||||
},
|
||||
"styleInstall": {
|
||||
"message": "「$stylename$」を Stylus にインストールしますか?",
|
||||
"message": "「$stylename$」を Stylus にインストールしますか?",
|
||||
"description": "Confirmation when installing a style",
|
||||
"placeholders": {
|
||||
"stylename": {
|
||||
|
@ -290,6 +302,10 @@
|
|||
"message": "全スタイルを再チェックします。私はスタイルを編集していません!",
|
||||
"description": "Label for the button to apply all detected updates"
|
||||
},
|
||||
"manageOnlyNonUsercss": {
|
||||
"message": "非Usercssスタイルのみ",
|
||||
"description": "Checkbox to show only non-Usercss (standard) styles"
|
||||
},
|
||||
"liveReloadLabel": {
|
||||
"message": "自動リロード",
|
||||
"description": "The label of live-reload feature"
|
||||
|
@ -314,6 +330,10 @@
|
|||
"message": "アクティブなスタイルの数を表示する",
|
||||
"description": "Label (must be very short) for the checkbox in the toolbar button context menu controlling toolbar badge text."
|
||||
},
|
||||
"popupHotkeysInfo": {
|
||||
"message": "<1>-<9>, <0>, または数字パッドキーによりN番目のスタイルの有効/無効を切り替えます (0は10番目になります)\n<A>-<Z> はその文字で始まる先頭のスタイルを切り替えます\n<Shift> は切り替えではなくエディターを開きます\n<Numpad +> はリストのスタイルをすべて有効にします\n<Numpad –> はリストのスタイルをすべて無効にします\n<Numpad *> と <`>(バッククォート)は初期状態が有効なスタイルのみを切り替えます。すなわち、ポップアップ上で後から有効にしたスタイルは切り替えません。例えば、テスト後に初期の選択に戻すには、全解除してから切り替えてください(すなわち<Numpad –> <Numpad *>)\n詳細は wiki を参照ください",
|
||||
"description": "NOTE1: preserve < and > symbols so that <hotkey> is styled as a key.\nNOTE2: the last line is displayed as a text of the link to the wiki page.\nNOTE3: this is the list of hotkeys displayed after clicking the right edge of the extension popup."
|
||||
},
|
||||
"cm_lineWrapping": {
|
||||
"message": "ワードラップ",
|
||||
"description": "Label for the checkbox controlling word wrap option for the style editor."
|
||||
|
@ -355,7 +375,7 @@
|
|||
"description": ""
|
||||
},
|
||||
"deleteStyleConfirm": {
|
||||
"message": "このスタイルを削除してもよろしいですか?",
|
||||
"message": "このスタイルを削除してもよろしいですか?",
|
||||
"description": "Confirmation before deleting a style"
|
||||
},
|
||||
"optionsCustomizePopup": {
|
||||
|
@ -392,7 +412,7 @@
|
|||
"description": "Label for the style maanger opener in the browser action context menu."
|
||||
},
|
||||
"styleUpdate": {
|
||||
"message": "「$stylename$」を更新してもよろしいですか?",
|
||||
"message": "「$stylename$」を更新してもよろしいですか?",
|
||||
"description": "Confirmation when updating a style",
|
||||
"placeholders": {
|
||||
"stylename": {
|
||||
|
@ -525,6 +545,10 @@
|
|||
"message": "オプション",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"usercssConfigIncomplete": {
|
||||
"message": "設定ダイアログの表示後に、スタイルが更新または削除されました。スタイルのメタデータの破損を避けるため、これらの変数は保存されませんでした:",
|
||||
"description": ""
|
||||
},
|
||||
"openManage": {
|
||||
"message": "管理",
|
||||
"description": "Link to open the manage page."
|
||||
|
@ -546,6 +570,10 @@
|
|||
"message": "更新をインストール",
|
||||
"description": "Label for the button to install an update for a single style"
|
||||
},
|
||||
"syncStorageErrorSaving": {
|
||||
"message": "値を保存できません。テキストの量を減らしてください。",
|
||||
"description": "Displayed when trying to save an excessively big value via storage.sync API"
|
||||
},
|
||||
"optionsCheckUpdate": {
|
||||
"message": "使用可能なすべての更新を確認してインストールする",
|
||||
"description": ""
|
||||
|
@ -801,7 +829,7 @@
|
|||
"description": "Label for the checkbox controlling 'edit' action behavior in the popup."
|
||||
},
|
||||
"dbError": {
|
||||
"message": "Stylusのデータベース使用中にエラーが発生しました。考えられる解決策を記載したWebページを開きますか?",
|
||||
"message": "Stylusのデータベース使用中にエラーが発生しました。考えられる解決策を記載したWebページを開きますか?",
|
||||
"description": "Prompt when a DB error is encountered"
|
||||
},
|
||||
"optionsAdvanced": {
|
||||
|
@ -844,6 +872,10 @@
|
|||
"message": "変更がありませんでした。",
|
||||
"description": "Message in the report shown after importing styles"
|
||||
},
|
||||
"confirmDiscardChanges": {
|
||||
"message": "変更を破棄しますか?",
|
||||
"description": "Generic label or title displayed when trying to close something (not a style) with unsaved changes"
|
||||
},
|
||||
"optionsActions": {
|
||||
"message": "アクション",
|
||||
"description": ""
|
||||
|
@ -885,6 +917,10 @@
|
|||
"message": "件の同一のスタイルをスキップしました",
|
||||
"description": "Text after the number of styles skipped due to being identical to the already installed ones in the report shown after importing styles"
|
||||
},
|
||||
"manageNewStyleAsUsercss": {
|
||||
"message": "Usercssとして",
|
||||
"description": "VERY SHORT label for the checkbox next to the 'Write new style' button in the style manager"
|
||||
},
|
||||
"optionsPopupWidth": {
|
||||
"message": "ポップアップの幅(ピクセル単位)",
|
||||
"description": ""
|
||||
|
@ -922,6 +958,10 @@
|
|||
"message": "元に戻す",
|
||||
"description": "Button label"
|
||||
},
|
||||
"usercssReplaceTemplateConfirmation": {
|
||||
"message": "現在のコードで、新しいUsercssスタイルのデフォルト・テンプレートを置き換えますか?",
|
||||
"description": ""
|
||||
},
|
||||
"cm_keyMap": {
|
||||
"message": "キーマップ",
|
||||
"description": "Label for the drop-down list controlling the keymap for the style editor."
|
||||
|
@ -979,6 +1019,10 @@
|
|||
"message": "HTML[stylus-iframe] によってiframeへのアクセスを可能にします",
|
||||
"description": ""
|
||||
},
|
||||
"usercssEditorNamePlaceholder": {
|
||||
"message": "コード内で @name を指定します",
|
||||
"description": "Placeholder text for the empty name input field when creating a new Usercss style"
|
||||
},
|
||||
"addStyleLabel": {
|
||||
"message": "新しいスタイルを作成",
|
||||
"description": "Label for the button to go to the add style page"
|
||||
|
@ -1046,5 +1090,9 @@
|
|||
"confirmClose": {
|
||||
"message": "閉じる",
|
||||
"description": "'Close' button in a confirm dialog"
|
||||
},
|
||||
"usercssReplaceTemplateName": {
|
||||
"message": "@name を空にすると、デフォルト・テンプレートを置き換えます",
|
||||
"description": "The text shown after @name when creating a new Usercss style"
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@
|
|||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"installButton": {
|
||||
"message": "Zainstaluj",
|
||||
"message": "Zainstaluj styl",
|
||||
"description": "Label for install button"
|
||||
},
|
||||
"styleMetaErrorCheckbox": {
|
||||
|
@ -47,6 +47,10 @@
|
|||
"message": "Nieprawidłowy format JSON",
|
||||
"description": "Setting linter config with invalid JSON"
|
||||
},
|
||||
"popupHotkeysTooltip": {
|
||||
"message": "Kliknij, aby zobaczyć dostępne skróty klawiszowe",
|
||||
"description": "Tooltip displayed when hovering the right edge of the extension popup"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Kolor tła",
|
||||
"description": ""
|
||||
|
@ -326,6 +330,10 @@
|
|||
"message": "Pokaż liczbę aktywnych stylów",
|
||||
"description": "Label (must be very short) for the checkbox in the toolbar button context menu controlling toolbar badge text."
|
||||
},
|
||||
"popupHotkeysInfo": {
|
||||
"message": "<1>-<9>, <0>, również na klawiaturze numerycznej - przełącza n-ty styl (0 to 10)\n<A>-<Z> przełącza pierwszy styl z nazwą zaczynającą się na literę\n<Shift> otwiera edytor zamiast przełączać\n<Numpad +> włącza wymienione style\n<Numpad –> wyłącza wymienione style\n<Numpad *> oraz <`> (grawis) - przełącza początkowo włączone style; nie ma zastosowania do później włączonych stylów, podczas gdy okienko podręczne jest otwarte, więc możesz przywrócić początkowy wybór po przetestowaniu: po prostu wyłącz wszystkie, a następnie przełącz, np. <Numpad –> <Numpad *>\nWięcej informacji na wiki",
|
||||
"description": "NOTE1: preserve < and > symbols so that <hotkey> is styled as a key.\nNOTE2: the last line is displayed as a text of the link to the wiki page.\nNOTE3: this is the list of hotkeys displayed after clicking the right edge of the extension popup."
|
||||
},
|
||||
"cm_lineWrapping": {
|
||||
"message": "Zawijanie tekstu",
|
||||
"description": "Label for the checkbox controlling word wrap option for the style editor."
|
||||
|
@ -537,6 +545,10 @@
|
|||
"message": "Opcje",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"usercssConfigIncomplete": {
|
||||
"message": "Styl został zaktualizowany lub usunięty po wyświetleniu okna dialogowego konfiguracji. Te zmienne nie zostały zapisane, aby uniknąć uszkodzenia metadanych stylu:",
|
||||
"description": ""
|
||||
},
|
||||
"openManage": {
|
||||
"message": "Zarządzaj",
|
||||
"description": "Link to open the manage page."
|
||||
|
@ -558,6 +570,10 @@
|
|||
"message": "Zainstaluj aktualizację",
|
||||
"description": "Label for the button to install an update for a single style"
|
||||
},
|
||||
"syncStorageErrorSaving": {
|
||||
"message": "Nie można zapisać wartości. Spróbuj zmniejszyć ilość tekstu.",
|
||||
"description": "Displayed when trying to save an excessively big value via storage.sync API"
|
||||
},
|
||||
"optionsCheckUpdate": {
|
||||
"message": "Sprawdź i zainstaluj wszystkie dostępne aktualizacje",
|
||||
"description": ""
|
||||
|
@ -868,6 +884,10 @@
|
|||
"message": "Nic nie zostało zmienione.",
|
||||
"description": "Message in the report shown after importing styles"
|
||||
},
|
||||
"confirmDiscardChanges": {
|
||||
"message": "Odrzucić zmiany?",
|
||||
"description": "Generic label or title displayed when trying to close something (not a style) with unsaved changes"
|
||||
},
|
||||
"optionsActions": {
|
||||
"message": "Akcje",
|
||||
"description": ""
|
||||
|
@ -922,7 +942,7 @@
|
|||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"installButtonReinstall": {
|
||||
"message": "Przeinstaluj",
|
||||
"message": "Przeinstaluj styl",
|
||||
"description": "Label for reinstall button"
|
||||
},
|
||||
"linterInvalidConfigError": {
|
||||
|
@ -950,6 +970,10 @@
|
|||
"message": "Cofnij",
|
||||
"description": "Button label"
|
||||
},
|
||||
"usercssReplaceTemplateConfirmation": {
|
||||
"message": "Zastąpić domyślny szablon dla nowych stylów Usercss aktualnym kodem?",
|
||||
"description": ""
|
||||
},
|
||||
"cm_keyMap": {
|
||||
"message": "Mapa klawiszy",
|
||||
"description": "Label for the drop-down list controlling the keymap for the style editor."
|
||||
|
@ -1007,6 +1031,10 @@
|
|||
"message": "Odsłoń ramki pływające za pomocą HTML[stylus-iframe]",
|
||||
"description": ""
|
||||
},
|
||||
"usercssEditorNamePlaceholder": {
|
||||
"message": "Określ @name w kodzie",
|
||||
"description": "Placeholder text for the empty name input field when creating a new Usercss style"
|
||||
},
|
||||
"addStyleLabel": {
|
||||
"message": "Napisz nowy styl",
|
||||
"description": "Label for the button to go to the add style page"
|
||||
|
@ -1016,7 +1044,7 @@
|
|||
"description": ""
|
||||
},
|
||||
"installButtonUpdate": {
|
||||
"message": "Zaktualizuj",
|
||||
"message": "Zaktualizuj styl",
|
||||
"description": "Label for update button"
|
||||
},
|
||||
"backupButtons": {
|
||||
|
@ -1032,7 +1060,7 @@
|
|||
"description": "Label for the button to go to the edit style page"
|
||||
},
|
||||
"installButtonInstalled": {
|
||||
"message": "Zainstalowany",
|
||||
"message": "Styl zainstalowano",
|
||||
"description": "Text displayed when the style is successfully installed"
|
||||
},
|
||||
"author": {
|
||||
|
@ -1074,5 +1102,9 @@
|
|||
"confirmClose": {
|
||||
"message": "Zamknij",
|
||||
"description": "'Close' button in a confirm dialog"
|
||||
},
|
||||
"usercssReplaceTemplateName": {
|
||||
"message": "Puste @name zastępuje szablon domyślny",
|
||||
"description": "The text shown after @name when creating a new Usercss style"
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@
|
|||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"installButton": {
|
||||
"message": "Установить",
|
||||
"message": "Установить стиль",
|
||||
"description": "Label for install button"
|
||||
},
|
||||
"styleMetaErrorCheckbox": {
|
||||
|
@ -47,6 +47,10 @@
|
|||
"message": "Ошибка формата JSON",
|
||||
"description": "Setting linter config with invalid JSON"
|
||||
},
|
||||
"popupHotkeysTooltip": {
|
||||
"message": "Показать клавиатурные сочетания",
|
||||
"description": "Tooltip displayed when hovering the right edge of the extension popup"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Цвет фона",
|
||||
"description": ""
|
||||
|
@ -330,6 +334,10 @@
|
|||
"message": "Число активных стилей",
|
||||
"description": "Label (must be very short) for the checkbox in the toolbar button context menu controlling toolbar badge text."
|
||||
},
|
||||
"popupHotkeysInfo": {
|
||||
"message": "<1>-<9>, <0>, и цифровой блок - переключает стиль по номеру (0 это 10)\n<A>-<Z> переключает стиль начинающийся с нажатой буквы\n<Shift> открывает в редакторе вместо переключения\n<Numpad +> включает стили в списке\n<Numpad –> выключает стили в списке\n<Numpad *> и <`> (обратный апостроф) - переключает изначально включенные стили вне зависимости от последующего переключения других ранее не включенных стилей, так что можно потестировать и восстановить исходный список нажав <Numpad –> <Numpad *>\nПодробнее на вики.",
|
||||
"description": "NOTE1: preserve < and > symbols so that <hotkey> is styled as a key.\nNOTE2: the last line is displayed as a text of the link to the wiki page.\nNOTE3: this is the list of hotkeys displayed after clicking the right edge of the extension popup."
|
||||
},
|
||||
"cm_lineWrapping": {
|
||||
"message": "Перенос по словам",
|
||||
"description": "Label for the checkbox controlling word wrap option for the style editor."
|
||||
|
@ -541,6 +549,10 @@
|
|||
"message": "Настройки",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"usercssConfigIncomplete": {
|
||||
"message": "Стиль был обновлен или удален после вызова окна настройки. Следующие настройки не были сохранены, чтобы не повредить метаданные стиля:",
|
||||
"description": ""
|
||||
},
|
||||
"openManage": {
|
||||
"message": "Менеджер",
|
||||
"description": "Link to open the manage page."
|
||||
|
@ -562,6 +574,10 @@
|
|||
"message": "Установить обновление",
|
||||
"description": "Label for the button to install an update for a single style"
|
||||
},
|
||||
"syncStorageErrorSaving": {
|
||||
"message": "Ошибка сохранения. Попробуйте уменьшить количество текста.",
|
||||
"description": "Displayed when trying to save an excessively big value via storage.sync API"
|
||||
},
|
||||
"optionsCheckUpdate": {
|
||||
"message": "Найти и установить обновления стилей",
|
||||
"description": ""
|
||||
|
@ -868,6 +884,10 @@
|
|||
"message": "Ничего не изменилось.",
|
||||
"description": "Message in the report shown after importing styles"
|
||||
},
|
||||
"confirmDiscardChanges": {
|
||||
"message": "Отказаться от изменений?",
|
||||
"description": "Generic label or title displayed when trying to close something (not a style) with unsaved changes"
|
||||
},
|
||||
"optionsActions": {
|
||||
"message": "Другие действия",
|
||||
"description": ""
|
||||
|
@ -922,7 +942,7 @@
|
|||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"installButtonReinstall": {
|
||||
"message": "Переустановить",
|
||||
"message": "Переустановить стиль",
|
||||
"description": "Label for reinstall button"
|
||||
},
|
||||
"linterInvalidConfigError": {
|
||||
|
@ -950,6 +970,10 @@
|
|||
"message": "Отменить",
|
||||
"description": "Button label"
|
||||
},
|
||||
"usercssReplaceTemplateConfirmation": {
|
||||
"message": "Заменить шаблон по умолчанию для нового стиля в формате Usercss текущим кодом?",
|
||||
"description": ""
|
||||
},
|
||||
"cm_keyMap": {
|
||||
"message": "Раскладка",
|
||||
"description": "Label for the drop-down list controlling the keymap for the style editor."
|
||||
|
@ -1007,6 +1031,10 @@
|
|||
"message": "Выявлять iframe путем добавления HTML[stylus-iframe]",
|
||||
"description": ""
|
||||
},
|
||||
"usercssEditorNamePlaceholder": {
|
||||
"message": "Укажите имя после @name в коде",
|
||||
"description": "Placeholder text for the empty name input field when creating a new Usercss style"
|
||||
},
|
||||
"addStyleLabel": {
|
||||
"message": "Создать стиль",
|
||||
"description": "Label for the button to go to the add style page"
|
||||
|
@ -1016,7 +1044,7 @@
|
|||
"description": ""
|
||||
},
|
||||
"installButtonUpdate": {
|
||||
"message": "Обновить",
|
||||
"message": "Обновить стиль",
|
||||
"description": "Label for update button"
|
||||
},
|
||||
"backupButtons": {
|
||||
|
@ -1032,7 +1060,7 @@
|
|||
"description": "Label for the button to go to the edit style page"
|
||||
},
|
||||
"installButtonInstalled": {
|
||||
"message": "Установлен",
|
||||
"message": "Стиль установлен",
|
||||
"description": "Text displayed when the style is successfully installed"
|
||||
},
|
||||
"author": {
|
||||
|
@ -1074,5 +1102,9 @@
|
|||
"confirmClose": {
|
||||
"message": "Закрыть",
|
||||
"description": "'Close' button in a confirm dialog"
|
||||
},
|
||||
"usercssReplaceTemplateName": {
|
||||
"message": "Пустой @name заменяет шаблон по умолчанию",
|
||||
"description": "The text shown after @name when creating a new Usercss style"
|
||||
}
|
||||
}
|
|
@ -19,6 +19,10 @@
|
|||
"message": "匯出樣式",
|
||||
"description": ""
|
||||
},
|
||||
"manageOnlyUsercss": {
|
||||
"message": "僅 Usercss 樣式",
|
||||
"description": "Checkbox to show only Usercss styles"
|
||||
},
|
||||
"optionsUpdateInterval": {
|
||||
"message": "自動檢查並安裝可用的使用者樣式更新(以小時計)",
|
||||
"description": ""
|
||||
|
@ -83,6 +87,10 @@
|
|||
"message": "因為不正確的 'regexp()' 使用導致未套用",
|
||||
"description": "Tooltip in the popup for styles that were not applied at all"
|
||||
},
|
||||
"colorpickerSwitchFormatTooltip": {
|
||||
"message": "切換格式:HEX → RGB → HSL。\nShift 並點選則為反向進行。\n也可以使用 PgUp (PageUp) 與 PgDn (PageDown) 鍵。",
|
||||
"description": "Tooltip for the switch button in the color picker popup in the style editor."
|
||||
},
|
||||
"styleRegexpInvalidExplanation": {
|
||||
"message": "部份 'regexp()' 歸則可能不再能被編譯。",
|
||||
"description": ""
|
||||
|
@ -294,6 +302,10 @@
|
|||
"message": "再次檢查,我沒有編輯任何樣式!",
|
||||
"description": "Label for the button to apply all detected updates"
|
||||
},
|
||||
"manageOnlyNonUsercss": {
|
||||
"message": "僅非 Usercss 樣式",
|
||||
"description": "Checkbox to show only non-Usercss (standard) styles"
|
||||
},
|
||||
"liveReloadLabel": {
|
||||
"message": "即時重新整理",
|
||||
"description": "The label of live-reload feature"
|
||||
|
@ -529,6 +541,10 @@
|
|||
"message": "選項",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"usercssConfigIncomplete": {
|
||||
"message": "在設定對話框顯示後,樣式已更新或刪除。這個變數將不會儲存,以避免損毀樣式的詮釋資料。",
|
||||
"description": ""
|
||||
},
|
||||
"openManage": {
|
||||
"message": "管理已安裝樣式",
|
||||
"description": "Link to open the manage page."
|
||||
|
@ -550,6 +566,10 @@
|
|||
"message": "安裝更新",
|
||||
"description": "Label for the button to install an update for a single style"
|
||||
},
|
||||
"syncStorageErrorSaving": {
|
||||
"message": "無法儲存值。嘗試減少文字量。",
|
||||
"description": "Displayed when trying to save an excessively big value via storage.sync API"
|
||||
},
|
||||
"optionsCheckUpdate": {
|
||||
"message": "檢查並安裝所有可用的更新",
|
||||
"description": ""
|
||||
|
@ -856,6 +876,10 @@
|
|||
"message": "沒有變更。",
|
||||
"description": "Message in the report shown after importing styles"
|
||||
},
|
||||
"confirmDiscardChanges": {
|
||||
"message": "放棄變更?",
|
||||
"description": "Generic label or title displayed when trying to close something (not a style) with unsaved changes"
|
||||
},
|
||||
"optionsActions": {
|
||||
"message": "動作",
|
||||
"description": ""
|
||||
|
@ -897,6 +921,10 @@
|
|||
"message": "已跳過相同的",
|
||||
"description": "Text after the number of styles skipped due to being identical to the already installed ones in the report shown after importing styles"
|
||||
},
|
||||
"manageNewStyleAsUsercss": {
|
||||
"message": "做為 Usercss",
|
||||
"description": "VERY SHORT label for the checkbox next to the 'Write new style' button in the style manager"
|
||||
},
|
||||
"optionsPopupWidth": {
|
||||
"message": "彈出視窗寬度(以像素計)",
|
||||
"description": ""
|
||||
|
@ -934,6 +962,10 @@
|
|||
"message": "撤銷",
|
||||
"description": "Button label"
|
||||
},
|
||||
"usercssReplaceTemplateConfirmation": {
|
||||
"message": "為新的 Usercss 樣式取代預設的範本為目前的程式碼?",
|
||||
"description": ""
|
||||
},
|
||||
"cm_keyMap": {
|
||||
"message": "鍵盤映射",
|
||||
"description": "Label for the drop-down list controlling the keymap for the style editor."
|
||||
|
@ -991,6 +1023,10 @@
|
|||
"message": "透過 HTML[stylus-iframe] 公開 iframes",
|
||||
"description": ""
|
||||
},
|
||||
"usercssEditorNamePlaceholder": {
|
||||
"message": "在程式碼中指定 @name",
|
||||
"description": "Placeholder text for the empty name input field when creating a new Usercss style"
|
||||
},
|
||||
"addStyleLabel": {
|
||||
"message": "編寫新樣式",
|
||||
"description": "Label for the button to go to the add style page"
|
||||
|
@ -1058,5 +1094,9 @@
|
|||
"confirmClose": {
|
||||
"message": "關閉",
|
||||
"description": "'Close' button in a confirm dialog"
|
||||
},
|
||||
"usercssReplaceTemplateName": {
|
||||
"message": "清空 @name 取代目前範本",
|
||||
"description": "The text shown after @name when creating a new Usercss style"
|
||||
}
|
||||
}
|
|
@ -147,9 +147,13 @@ if (chrome.contextMenus) {
|
|||
chrome.contextMenus.create(item, ignoreChromeError);
|
||||
}
|
||||
};
|
||||
const toggleCheckmark = (id, checked) => {
|
||||
chrome.contextMenus.update(id, {checked}, ignoreChromeError);
|
||||
};
|
||||
|
||||
// circumvent the bug with disabling check marks in Chrome 62+
|
||||
// TODO: replace 1e6 with the actual rev. number when/if the bug is fixed
|
||||
const toggleCheckmark = CHROME >= 3172 && CHROME <= 1e6 ?
|
||||
(id => chrome.contextMenus.remove(id, () => createContextMenus([id]) + ignoreChromeError())) :
|
||||
((id, checked) => chrome.contextMenus.update(id, {checked}, ignoreChromeError));
|
||||
|
||||
const togglePresence = (id, checked) => {
|
||||
if (checked) {
|
||||
createContextMenus([id]);
|
||||
|
@ -157,6 +161,7 @@ if (chrome.contextMenus) {
|
|||
chrome.contextMenus.remove(id, ignoreChromeError);
|
||||
}
|
||||
};
|
||||
|
||||
const keys = Object.keys(contextMenus);
|
||||
prefs.subscribe(keys.filter(id => typeof prefs.readOnlyValues[id] === 'boolean'), toggleCheckmark);
|
||||
prefs.subscribe(keys.filter(id => contextMenus[id].presentIf), togglePresence);
|
||||
|
|
38
edit.html
38
edit.html
|
@ -5,7 +5,7 @@
|
|||
|
||||
<style id="firefox-transitions-bug-suppressor">
|
||||
/* restrict to FF */
|
||||
@-moz-document url-prefix("") {
|
||||
@supports (-moz-appearance:none) {
|
||||
/* increased specificity to override sane selectors in user styles */
|
||||
html#stylus.firefox #stylus-edit #header *,
|
||||
html#stylus.firefox #stylus-edit #sections * {
|
||||
|
@ -28,6 +28,9 @@
|
|||
<script src="edit/applies-to-line-widget.js"></script>
|
||||
<script src="edit/source-editor.js"></script>
|
||||
<script src="edit/colorpicker-helper.js"></script>
|
||||
<script src="edit/beautify.js"></script>
|
||||
<script src="edit/sections.js"></script>
|
||||
<script src="edit/show-keymap-help.js"></script>
|
||||
<script src="edit/edit.js"></script>
|
||||
|
||||
<script src="vendor/codemirror/lib/codemirror.js"></script>
|
||||
|
@ -62,8 +65,10 @@
|
|||
<script src="vendor/codemirror/keymap/emacs.js"></script>
|
||||
<script src="vendor/codemirror/keymap/vim.js"></script>
|
||||
|
||||
<script src="/edit/match-highlighter-helper.js"></script>
|
||||
<script src="/edit/codemirror-default.js"></script>
|
||||
<script src="edit/match-highlighter-helper.js"></script>
|
||||
<script src="edit/codemirror-editing-hooks.js"></script>
|
||||
<script src="edit/codemirror-default.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="/edit/codemirror-default.css">
|
||||
<link id="cm-theme" rel="stylesheet">
|
||||
|
||||
|
@ -80,11 +85,13 @@
|
|||
<button class="add-applies-to" i18n-text="appliesAdd"></button>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<template data-id="appliesToEverything">
|
||||
<li class="applies-to-everything" i18n-text="appliesToEverything">
|
||||
<button class="add-applies-to" i18n-text="appliesSpecify"></button>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<template data-id="section">
|
||||
<div>
|
||||
<label i18n-text="sectionCode" class="code-label"></label>
|
||||
|
@ -101,25 +108,30 @@
|
|||
<button class="test-regexp" i18n-text="styleRegexpTestButton"></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template data-id="find">
|
||||
<span i18n-text="search">: <input type="text" class="CodeMirror-search-field" spellcheck="false">
|
||||
<span class="CodeMirror-search-hint">(<span i18n-text="searchRegexp"></span>)</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template data-id="replace">
|
||||
<span i18n-text="replace">: <input type="text" class="CodeMirror-search-field" spellcheck="false">
|
||||
<span class="CodeMirror-search-hint">(<span i18n-text="searchRegexp"></span>)</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template data-id="replaceAll">
|
||||
<span i18n-text="replaceAll">: <input type="text" class="CodeMirror-search-field" spellcheck="false">
|
||||
<span class="CodeMirror-search-hint">(<span i18n-text="searchRegexp"></span>)</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template data-id="replaceWith">
|
||||
<span i18n-text="replaceWith">: <input type="text" class="CodeMirror-search-field" spellcheck="false">
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template data-id="replaceConfirm">
|
||||
<span i18n-text="replace">?
|
||||
<button i18n-text="confirmYes"></button>
|
||||
|
@ -127,15 +139,35 @@
|
|||
<button i18n-text="confirmStop"></button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template data-id="jumpToLine">
|
||||
<span i18n-text="editGotoLine">: <input class="CodeMirror-jump-field" type="text"></span>
|
||||
</template>
|
||||
|
||||
<template data-id="regexpTestPartial">
|
||||
<a target="_blank" href="https://github.com/stylish-userstyles/stylish/wiki/Applying-styles-to-specific-sites#advanced-matching-with-regular-expressions"><svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg></a>
|
||||
</template>
|
||||
|
||||
<template data-id="resizeGrip">
|
||||
<div class="resize-grip" i18n-title="cm_resizeGripHint"></div>
|
||||
</template>
|
||||
|
||||
<template data-id="keymapHelp">
|
||||
<table class="keymap-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input i18n-placeholder="helpKeyMapHotkey" type="search" class="can-close-on-esc"></th>
|
||||
<th><input i18n-placeholder="helpKeyMapCommand" type="search" class="can-close-on-esc"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
</head>
|
||||
|
||||
<body id="stylus-edit">
|
||||
|
|
96
edit/beautify.js
Normal file
96
edit/beautify.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
global CodeMirror loadScript css_beautify
|
||||
global editors getSectionForChild showHelp
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
function beautify(event) {
|
||||
loadScript('/vendor-overwrites/beautify/beautify-css-mod.js')
|
||||
.then(() => {
|
||||
if (!window.css_beautify && window.exports) {
|
||||
window.css_beautify = window.exports.css_beautify;
|
||||
}
|
||||
})
|
||||
.then(doBeautify);
|
||||
|
||||
function doBeautify() {
|
||||
const tabs = prefs.get('editor.indentWithTabs');
|
||||
const options = prefs.get('editor.beautify');
|
||||
options.indent_size = tabs ? 1 : prefs.get('editor.tabSize');
|
||||
options.indent_char = tabs ? '\t' : ' ';
|
||||
|
||||
const section = getSectionForChild(event.target);
|
||||
const scope = section ? [section.CodeMirror] : editors;
|
||||
|
||||
showHelp(t('styleBeautify'), '<div class="beautify-options">' +
|
||||
optionHtml('.selector1,', 'selector_separator_newline') +
|
||||
optionHtml('.selector2,', 'newline_before_open_brace') +
|
||||
optionHtml('{', 'newline_after_open_brace') +
|
||||
optionHtml('border: none;', 'newline_between_properties', true) +
|
||||
optionHtml('display: block;', 'newline_before_close_brace', true) +
|
||||
optionHtml('}', 'newline_between_rules') +
|
||||
`<label style="display: block; clear: both;"><input data-option="indent_conditional" type="checkbox"
|
||||
${options.indent_conditional !== false ? 'checked' : ''}>` +
|
||||
t('styleBeautifyIndentConditional') + '</label>' +
|
||||
'</div>' +
|
||||
'<div><button role="undo"></button></div>');
|
||||
|
||||
const undoButton = $('#help-popup button[role="undo"]');
|
||||
undoButton.textContent = t(scope.length === 1 ? 'undo' : 'undoGlobal');
|
||||
undoButton.addEventListener('click', () => {
|
||||
let undoable = false;
|
||||
scope.forEach(cm => {
|
||||
if (cm.beautifyChange && cm.beautifyChange[cm.changeGeneration()]) {
|
||||
delete cm.beautifyChange[cm.changeGeneration()];
|
||||
cm.undo();
|
||||
cm.scrollIntoView(cm.getCursor());
|
||||
undoable |= cm.beautifyChange[cm.changeGeneration()];
|
||||
}
|
||||
});
|
||||
undoButton.disabled = !undoable;
|
||||
});
|
||||
|
||||
scope.forEach(cm => {
|
||||
setTimeout(() => {
|
||||
const pos = options.translate_positions =
|
||||
[].concat.apply([], cm.doc.sel.ranges.map(r =>
|
||||
[Object.assign({}, r.anchor), Object.assign({}, r.head)]));
|
||||
const text = cm.getValue();
|
||||
const newText = css_beautify(text, options);
|
||||
if (newText !== text) {
|
||||
if (!cm.beautifyChange || !cm.beautifyChange[cm.changeGeneration()]) {
|
||||
// clear the list if last change wasn't a css-beautify
|
||||
cm.beautifyChange = {};
|
||||
}
|
||||
cm.setValue(newText);
|
||||
const selections = [];
|
||||
for (let i = 0; i < pos.length; i += 2) {
|
||||
selections.push({anchor: pos[i], head: pos[i + 1]});
|
||||
}
|
||||
cm.setSelections(selections);
|
||||
cm.beautifyChange[cm.changeGeneration()] = true;
|
||||
undoButton.disabled = false;
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$('.beautify-options').onchange = ({target}) => {
|
||||
const value = target.type === 'checkbox' ? target.checked : target.selectedIndex > 0;
|
||||
prefs.set('editor.beautify', Object.assign(options, {[target.dataset.option]: value}));
|
||||
if (target.parentNode.hasAttribute('newline')) {
|
||||
target.parentNode.setAttribute('newline', value.toString());
|
||||
}
|
||||
doBeautify();
|
||||
};
|
||||
|
||||
function optionHtml(label, optionName, indent) {
|
||||
const value = options[optionName];
|
||||
return '<div newline="' + value.toString() + '">' +
|
||||
'<span' + (indent ? ' indent' : '') + '>' + label + '</span>' +
|
||||
'<select data-option="' + optionName + '">' +
|
||||
'<option' + (value ? '' : ' selected') + '> </option>' +
|
||||
'<option' + (value ? ' selected' : '') + '>\\n</option>' +
|
||||
'</select></div>';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
outline: -webkit-focus-ring-color auto 5px;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
@-moz-document url-prefix("") {
|
||||
@supports (-moz-appearance:none) {
|
||||
/* restrict to FF */
|
||||
.CodeMirror-focused {
|
||||
outline: #7dadd9 auto 1px;
|
||||
|
@ -45,3 +45,18 @@
|
|||
from { background-color: rgba(255, 255, 0, .4); } /* search color */
|
||||
to { background-color: rgba(100, 255, 100, .4); } /* sarch + highlight */
|
||||
}
|
||||
|
||||
.CodeMirror-activeline .applies-to:before {
|
||||
background-color: hsla(214, 100%, 90%, 0.15);
|
||||
content: "";
|
||||
top: 1em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 1em;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.CodeMirror-activeline .applies-to ul {
|
||||
z-index: 2;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
const defaults = {
|
||||
mode: 'css',
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
lineWrapping: prefs.get('editor.lineWrapping'),
|
||||
foldGutter: true,
|
||||
gutters: [
|
||||
'CodeMirror-linenumbers',
|
||||
|
@ -30,7 +30,8 @@
|
|||
'Alt-Enter': 'toggleStyle',
|
||||
'Alt-PageDown': 'nextEditor',
|
||||
'Alt-PageUp': 'prevEditor'
|
||||
}
|
||||
},
|
||||
maxHighlightLength: 100e3,
|
||||
};
|
||||
|
||||
Object.assign(CodeMirror.defaults, defaults, prefs.get('editor.options'));
|
||||
|
|
687
edit/codemirror-editing-hooks.js
Normal file
687
edit/codemirror-editing-hooks.js
Normal file
|
@ -0,0 +1,687 @@
|
|||
/*
|
||||
global CodeMirror linterConfig loadScript
|
||||
global editors editor styleId
|
||||
global save toggleStyle setupAutocomplete makeSectionVisible getSectionForChild
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
onDOMready().then(() => {
|
||||
CodeMirror.defaults.lint = linterConfig.getForCodeMirror();
|
||||
|
||||
const COMMANDS = {
|
||||
save,
|
||||
toggleStyle,
|
||||
jumpToLine,
|
||||
nextEditor, prevEditor,
|
||||
find, findNext, findPrev, replace, replaceAll,
|
||||
};
|
||||
// reroute handling to nearest editor when keypress resolves to one of these commands
|
||||
const REROUTED = new Set([
|
||||
...Object.keys(COMMANDS),
|
||||
'colorpicker',
|
||||
]);
|
||||
|
||||
const ORIGINAL_COMMAND = {
|
||||
find: CodeMirror.commands.find,
|
||||
findNext: CodeMirror.commands.findNext,
|
||||
findPrev: CodeMirror.commands.findPrev,
|
||||
replace: CodeMirror.commands.replace
|
||||
};
|
||||
const ORIGINAL_METHOD = {
|
||||
openDialog: CodeMirror.prototype.openDialog,
|
||||
openConfirm: CodeMirror.prototype.openConfirm,
|
||||
};
|
||||
|
||||
Object.assign(CodeMirror, {
|
||||
getOption,
|
||||
setOption,
|
||||
});
|
||||
Object.assign(CodeMirror.commands,
|
||||
COMMANDS);
|
||||
Object.assign(CodeMirror.prototype, {
|
||||
getSection,
|
||||
rerouteHotkeys,
|
||||
});
|
||||
|
||||
// cm.state.search for last used 'find'
|
||||
let searchState;
|
||||
|
||||
// N.B. the event listener should be registered before setupLivePrefs()
|
||||
$('#options').addEventListener('change', onOptionElementChanged);
|
||||
buildOptionsElements();
|
||||
setupLivePrefs();
|
||||
rerouteHotkeys(true);
|
||||
|
||||
return;
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
function getOption(o) {
|
||||
return CodeMirror.defaults[o];
|
||||
}
|
||||
|
||||
function setOption(o, v) {
|
||||
CodeMirror.defaults[o] = v;
|
||||
if (editors.length > 4 && (o === 'theme' || o === 'lineWrapping')) {
|
||||
throttleSetOption({key: o, value: v, index: 0});
|
||||
return;
|
||||
}
|
||||
editors.forEach(editor => {
|
||||
editor.setOption(o, v);
|
||||
});
|
||||
}
|
||||
|
||||
function throttleSetOption({
|
||||
key,
|
||||
value,
|
||||
index,
|
||||
timeStart = performance.now(),
|
||||
cmStart = editors.lastActive || editors[0],
|
||||
editorsCopy = editors.slice(),
|
||||
progress,
|
||||
}) {
|
||||
if (index === 0) {
|
||||
if (!cmStart) {
|
||||
return;
|
||||
}
|
||||
cmStart.setOption(key, value);
|
||||
}
|
||||
|
||||
const THROTTLE_AFTER_MS = 100;
|
||||
const THROTTLE_SHOW_PROGRESS_AFTER_MS = 100;
|
||||
|
||||
const t0 = performance.now();
|
||||
const total = editorsCopy.length;
|
||||
while (index < total) {
|
||||
const cm = editorsCopy[index++];
|
||||
if (cm === cmStart ||
|
||||
cm !== editors[index] && !editors.includes(cm)) {
|
||||
continue;
|
||||
}
|
||||
cm.setOption(key, value);
|
||||
if (performance.now() - t0 > THROTTLE_AFTER_MS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index >= total) {
|
||||
$.remove(progress);
|
||||
return;
|
||||
}
|
||||
if (!progress &&
|
||||
index < total / 2 &&
|
||||
t0 - timeStart > THROTTLE_SHOW_PROGRESS_AFTER_MS) {
|
||||
let option = $('#editor.' + key);
|
||||
if (option) {
|
||||
if (option.type === 'checkbox') {
|
||||
option = (option.labels || [])[0] || option.nextElementSibling || option;
|
||||
}
|
||||
progress = document.body.appendChild($element({
|
||||
className: 'set-option-progress',
|
||||
targetElement: option,
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (progress) {
|
||||
const optionBounds = progress.targetElement.getBoundingClientRect();
|
||||
const bounds = {
|
||||
top: optionBounds.top + window.scrollY + 1,
|
||||
left: optionBounds.left + window.scrollX + 1,
|
||||
width: (optionBounds.width - 2) * index / total | 0,
|
||||
height: optionBounds.height - 2,
|
||||
};
|
||||
const style = progress.style;
|
||||
for (const prop in bounds) {
|
||||
if (bounds[prop] !== parseFloat(style[prop])) {
|
||||
style[prop] = bounds[prop] + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(throttleSetOption, 0, {
|
||||
key,
|
||||
value,
|
||||
index,
|
||||
timeStart,
|
||||
cmStart,
|
||||
editorsCopy,
|
||||
progress,
|
||||
});
|
||||
}
|
||||
|
||||
function getSection() {
|
||||
return this.display.wrapper.parentNode;
|
||||
}
|
||||
|
||||
function nextEditor(cm) {
|
||||
nextPrevEditor(cm, 1);
|
||||
}
|
||||
|
||||
function prevEditor(cm) {
|
||||
nextPrevEditor(cm, -1);
|
||||
}
|
||||
|
||||
function nextPrevEditor(cm, direction) {
|
||||
cm = editors[(editors.indexOf(cm) + direction + editors.length) % editors.length];
|
||||
makeSectionVisible(cm);
|
||||
cm.focus();
|
||||
return cm;
|
||||
}
|
||||
|
||||
function jumpToLine(cm) {
|
||||
const cur = cm.getCursor();
|
||||
refocusMinidialog(cm);
|
||||
cm.openDialog(template.jumpToLine.cloneNode(true), str => {
|
||||
const m = str.match(/^\s*(\d+)(?:\s*:\s*(\d+))?\s*$/);
|
||||
if (m) {
|
||||
cm.setCursor(m[1] - 1, m[2] ? m[2] - 1 : cur.ch);
|
||||
}
|
||||
}, {value: cur.line + 1});
|
||||
}
|
||||
|
||||
function refocusMinidialog(cm) {
|
||||
const section = cm.getSection();
|
||||
if (!$('.CodeMirror-dialog', section)) {
|
||||
return;
|
||||
}
|
||||
// close the currently opened minidialog
|
||||
cm.focus();
|
||||
// make sure to focus the input in newly opened minidialog
|
||||
setTimeout(() => {
|
||||
$('.CodeMirror-dialog', section).focus();
|
||||
});
|
||||
}
|
||||
|
||||
function onOptionElementChanged(event) {
|
||||
const el = event.target;
|
||||
let option = el.id.replace(/^editor\./, '');
|
||||
if (!option) {
|
||||
console.error('no "cm_option"', el);
|
||||
return;
|
||||
}
|
||||
let value = el.type === 'checkbox' ? el.checked : el.value;
|
||||
switch (option) {
|
||||
case 'tabSize':
|
||||
value = Number(value);
|
||||
CodeMirror.setOption('indentUnit', value);
|
||||
break;
|
||||
|
||||
case 'theme': {
|
||||
const themeLink = $('#cm-theme');
|
||||
// use non-localized 'default' internally
|
||||
if (!value || value === 'default' || value === t('defaultTheme')) {
|
||||
value = 'default';
|
||||
if (prefs.get(el.id) !== value) {
|
||||
prefs.set(el.id, value);
|
||||
}
|
||||
themeLink.href = '';
|
||||
el.selectedIndex = 0;
|
||||
break;
|
||||
}
|
||||
const url = chrome.runtime.getURL('vendor/codemirror/theme/' + value + '.css');
|
||||
if (themeLink.href === url) {
|
||||
// preloaded in initCodeMirror()
|
||||
break;
|
||||
}
|
||||
// avoid flicker: wait for the second stylesheet to load, then apply the theme
|
||||
document.head.appendChild($element({
|
||||
tag: 'link',
|
||||
id: 'cm-theme2',
|
||||
rel: 'stylesheet',
|
||||
href: url
|
||||
}));
|
||||
setTimeout(() => {
|
||||
CodeMirror.setOption(option, value);
|
||||
themeLink.remove();
|
||||
$('#cm-theme2').id = 'cm-theme';
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
case 'autocompleteOnTyping':
|
||||
editors.forEach(cm => setupAutocomplete(cm, el.checked));
|
||||
return;
|
||||
|
||||
case 'autoCloseBrackets':
|
||||
Promise.resolve(value && loadScript('/vendor/codemirror/addon/edit/closebrackets.js')).then(() => {
|
||||
CodeMirror.setOption(option, value);
|
||||
});
|
||||
return;
|
||||
|
||||
case 'matchHighlight':
|
||||
switch (value) {
|
||||
case 'token':
|
||||
case 'selection':
|
||||
document.body.dataset[option] = value;
|
||||
value = {showToken: value === 'token' && /[#.\-\w]/, annotateScrollbar: true};
|
||||
break;
|
||||
default:
|
||||
value = null;
|
||||
}
|
||||
option = 'highlightSelectionMatches';
|
||||
break;
|
||||
|
||||
case 'colorpicker':
|
||||
return;
|
||||
}
|
||||
CodeMirror.setOption(option, value);
|
||||
}
|
||||
|
||||
function buildOptionsElements() {
|
||||
// no need to escape the period in the id
|
||||
const themeControl = $('#editor.theme');
|
||||
const themeList = localStorage.codeMirrorThemes;
|
||||
if (themeList) {
|
||||
optionsFromArray(themeControl, themeList.split(/\s+/));
|
||||
} else {
|
||||
// Chrome is starting up and shows our edit.html, but the background page isn't loaded yet
|
||||
const theme = prefs.get('editor.theme');
|
||||
optionsFromArray(themeControl, [theme === 'default' ? t('defaultTheme') : theme]);
|
||||
getCodeMirrorThemes().then(() => {
|
||||
const themes = (localStorage.codeMirrorThemes || '').split(/\s+/);
|
||||
optionsFromArray(themeControl, themes);
|
||||
themeControl.selectedIndex = Math.max(0, themes.indexOf(theme));
|
||||
});
|
||||
}
|
||||
optionsFromArray($('#editor.keyMap'), Object.keys(CodeMirror.keyMap).sort());
|
||||
}
|
||||
|
||||
function optionsFromArray(parent, options) {
|
||||
const fragment = document.createDocumentFragment();
|
||||
for (const opt of options) {
|
||||
fragment.appendChild($element({tag: 'option', textContent: opt}));
|
||||
}
|
||||
parent.appendChild(fragment);
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
|
||||
function shouldIgnoreCase(query) {
|
||||
// treat all-lowercase non-regexp queries as case-insensitive
|
||||
return typeof query === 'string' && query === query.toLowerCase();
|
||||
}
|
||||
|
||||
function updateState(cm, newState) {
|
||||
if (!newState) {
|
||||
if (cm.state.search) {
|
||||
return cm.state.search;
|
||||
}
|
||||
if (!searchState) {
|
||||
return null;
|
||||
}
|
||||
newState = searchState;
|
||||
}
|
||||
cm.state.search = {
|
||||
query: newState.query,
|
||||
overlay: newState.overlay,
|
||||
annotate: cm.showMatchesOnScrollbar(newState.query, shouldIgnoreCase(newState.query))
|
||||
};
|
||||
cm.addOverlay(newState.overlay);
|
||||
return cm.state.search;
|
||||
}
|
||||
|
||||
// overrides the original openDialog with a clone of the provided template
|
||||
function customizeOpenDialog(cm, template, callback) {
|
||||
cm.openDialog = (tmpl, cb, opt) => {
|
||||
// invoke 'callback' and bind 'this' to the original callback
|
||||
ORIGINAL_METHOD.openDialog.call(cm, template.cloneNode(true), callback.bind(cb), opt);
|
||||
};
|
||||
setTimeout(() => (cm.openDialog = ORIGINAL_METHOD.openDialog));
|
||||
refocusMinidialog(cm);
|
||||
}
|
||||
|
||||
function focusClosestCM(activeCM) {
|
||||
editors.lastActive = activeCM;
|
||||
const cm = getEditorInSight();
|
||||
if (cm !== activeCM) {
|
||||
cm.focus();
|
||||
}
|
||||
return cm;
|
||||
}
|
||||
|
||||
function find(activeCM) {
|
||||
activeCM = focusClosestCM(activeCM);
|
||||
customizeOpenDialog(activeCM, template.find, function (query) {
|
||||
this(query);
|
||||
searchState = activeCM.state.search;
|
||||
if (editors.length === 1 || !searchState.query) {
|
||||
return;
|
||||
}
|
||||
editors.forEach(cm => {
|
||||
if (cm !== activeCM) {
|
||||
cm.execCommand('clearSearch');
|
||||
updateState(cm, searchState);
|
||||
}
|
||||
});
|
||||
if (CodeMirror.cmpPos(searchState.posFrom, searchState.posTo) === 0) {
|
||||
findNext(activeCM);
|
||||
}
|
||||
});
|
||||
ORIGINAL_COMMAND.find(activeCM);
|
||||
}
|
||||
|
||||
function findNext(activeCM, reverse) {
|
||||
let state = updateState(activeCM);
|
||||
if (!state || !state.query) {
|
||||
find(activeCM);
|
||||
return;
|
||||
}
|
||||
let pos = activeCM.getCursor(reverse ? 'from' : 'to');
|
||||
// clear the selection, don't move the cursor
|
||||
activeCM.setSelection(activeCM.getCursor());
|
||||
|
||||
const rxQuery = typeof state.query === 'object'
|
||||
? state.query : stringAsRegExp(state.query, shouldIgnoreCase(state.query) ? 'i' : '');
|
||||
|
||||
if (
|
||||
document.activeElement &&
|
||||
document.activeElement.name === 'applies-value' &&
|
||||
searchAppliesTo(activeCM)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let cm = activeCM;
|
||||
for (let i = 0; i < editors.length; i++) {
|
||||
state = updateState(cm);
|
||||
if (!cm.hasFocus()) {
|
||||
pos = reverse ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(0, 0);
|
||||
}
|
||||
const searchCursor = cm.getSearchCursor(state.query, pos, shouldIgnoreCase(state.query));
|
||||
if (searchCursor.find(reverse)) {
|
||||
if (editors.length > 1) {
|
||||
makeSectionVisible(cm);
|
||||
cm.focus();
|
||||
}
|
||||
// speedup the original findNext
|
||||
state.posFrom = reverse ? searchCursor.to() : searchCursor.from();
|
||||
state.posTo = CodeMirror.Pos(state.posFrom.line, state.posFrom.ch);
|
||||
ORIGINAL_COMMAND[reverse ? 'findPrev' : 'findNext'](cm);
|
||||
return;
|
||||
} else if (!reverse && searchAppliesTo(cm)) {
|
||||
return;
|
||||
}
|
||||
cm = editors[(editors.indexOf(cm) + (reverse ? -1 + editors.length : 1)) % editors.length];
|
||||
if (reverse && searchAppliesTo(cm)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// nothing found so far, so call the original search with wrap-around
|
||||
ORIGINAL_COMMAND[reverse ? 'findPrev' : 'findNext'](activeCM);
|
||||
|
||||
function searchAppliesTo(cm) {
|
||||
let inputs = $$('.applies-value', cm.getSection());
|
||||
if (reverse) {
|
||||
inputs = inputs.reverse();
|
||||
}
|
||||
inputs.splice(0, inputs.indexOf(document.activeElement) + 1);
|
||||
return inputs.some(input => {
|
||||
const match = rxQuery.exec(input.value);
|
||||
if (match) {
|
||||
input.focus();
|
||||
const end = match.index + match[0].length;
|
||||
// scroll selected part into view in long inputs,
|
||||
// works only outside of current event handlers chain, hence timeout=0
|
||||
setTimeout(() => {
|
||||
input.setSelectionRange(end, end);
|
||||
input.setSelectionRange(match.index, end);
|
||||
}, 0);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function findPrev(cm) {
|
||||
findNext(cm, true);
|
||||
}
|
||||
|
||||
function replace(activeCM, all) {
|
||||
let queue;
|
||||
let query;
|
||||
let replacement;
|
||||
activeCM = focusClosestCM(activeCM);
|
||||
customizeOpenDialog(activeCM, template[all ? 'replaceAll' : 'replace'], function (txt) {
|
||||
query = txt;
|
||||
customizeOpenDialog(activeCM, template.replaceWith, txt => {
|
||||
replacement = txt;
|
||||
queue = editors.rotate(-editors.indexOf(activeCM));
|
||||
if (all) {
|
||||
editors.forEach(doReplace);
|
||||
} else {
|
||||
doReplace();
|
||||
}
|
||||
});
|
||||
this(query);
|
||||
});
|
||||
ORIGINAL_COMMAND.replace(activeCM, all);
|
||||
|
||||
function doReplace() {
|
||||
const cm = queue.shift();
|
||||
if (!cm) {
|
||||
if (!all) {
|
||||
editors.lastActive.focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// hide the first two dialogs (replace, replaceWith)
|
||||
cm.openDialog = (tmpl, callback) => {
|
||||
cm.openDialog = (tmpl, callback) => {
|
||||
cm.openDialog = ORIGINAL_METHOD.openDialog;
|
||||
if (all) {
|
||||
callback(replacement);
|
||||
} else {
|
||||
doConfirm(cm);
|
||||
callback(replacement);
|
||||
if (!$('.CodeMirror-dialog', cm.getWrapperElement())) {
|
||||
// no dialog == nothing found in the current CM, move to the next
|
||||
doReplace();
|
||||
}
|
||||
}
|
||||
};
|
||||
callback(query);
|
||||
};
|
||||
ORIGINAL_COMMAND.replace(cm, all);
|
||||
}
|
||||
function doConfirm(cm) {
|
||||
let wrapAround = false;
|
||||
const origPos = cm.getCursor();
|
||||
cm.openConfirm = function overrideConfirm(tmpl, callbacks, opt) {
|
||||
const ovrCallbacks = callbacks.map(callback => () => {
|
||||
makeSectionVisible(cm);
|
||||
cm.openConfirm = overrideConfirm;
|
||||
setTimeout(() => (cm.openConfirm = ORIGINAL_METHOD.openConfirm));
|
||||
|
||||
const pos = cm.getCursor();
|
||||
callback();
|
||||
const cmp = CodeMirror.cmpPos(cm.getCursor(), pos);
|
||||
wrapAround |= cmp <= 0;
|
||||
|
||||
const dlg = $('.CodeMirror-dialog', cm.getWrapperElement());
|
||||
if (!dlg || cmp === 0 || wrapAround && CodeMirror.cmpPos(cm.getCursor(), origPos) >= 0) {
|
||||
$.remove(dlg);
|
||||
doReplace();
|
||||
}
|
||||
});
|
||||
ORIGINAL_METHOD.openConfirm.call(cm, template.replaceConfirm.cloneNode(true), ovrCallbacks, opt);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function replaceAll(cm) {
|
||||
replace(cm, true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
function rerouteHotkeys(enable, immediately) {
|
||||
if (!immediately) {
|
||||
debounce(rerouteHotkeys, 0, enable, true);
|
||||
} else if (enable) {
|
||||
document.addEventListener('keydown', rerouteHandler);
|
||||
} else {
|
||||
document.removeEventListener('keydown', rerouteHandler);
|
||||
}
|
||||
}
|
||||
|
||||
function rerouteHandler(event) {
|
||||
const keyName = CodeMirror.keyName(event);
|
||||
if (!keyName) {
|
||||
return;
|
||||
}
|
||||
const rerouteCommand = name => {
|
||||
if (REROUTED.has(name)) {
|
||||
CodeMirror.commands[name](getEditorInSight(event.target));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
if (CodeMirror.lookupKey(keyName, CodeMirror.defaults.keyMap, rerouteCommand) === 'handled' ||
|
||||
CodeMirror.lookupKey(keyName, CodeMirror.defaults.extraKeys, rerouteCommand) === 'handled') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
function getEditorInSight(nearbyElement) {
|
||||
// priority: 1. associated CM for applies-to element 2. last active if visible 3. first visible
|
||||
let cm;
|
||||
if (nearbyElement && nearbyElement.className.indexOf('applies-') >= 0) {
|
||||
cm = getSectionForChild(nearbyElement).CodeMirror;
|
||||
} else {
|
||||
cm = editors.lastActive;
|
||||
}
|
||||
// closest editor should have at least 2 lines visible
|
||||
const lineHeight = editors[0].defaultTextHeight();
|
||||
const scrollY = window.scrollY;
|
||||
const windowBottom = scrollY + window.innerHeight - 2 * lineHeight;
|
||||
const allSectionsContainerTop = scrollY + $('#sections').getBoundingClientRect().top;
|
||||
const distances = [];
|
||||
const alreadyInView = cm && offscreenDistance(null, cm) === 0;
|
||||
return alreadyInView ? cm : findClosest();
|
||||
|
||||
function offscreenDistance(index, cm) {
|
||||
if (index >= 0 && distances[index] !== undefined) {
|
||||
return distances[index];
|
||||
}
|
||||
const section = (cm || editors[index]).getSection();
|
||||
const top = allSectionsContainerTop + section.offsetTop;
|
||||
if (top < scrollY + lineHeight) {
|
||||
return Math.max(0, scrollY - top - lineHeight);
|
||||
}
|
||||
if (top < windowBottom) {
|
||||
return 0;
|
||||
}
|
||||
const distance = top - windowBottom + section.offsetHeight;
|
||||
if (index >= 0) {
|
||||
distances[index] = distance;
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
function findClosest() {
|
||||
const last = editors.length - 1;
|
||||
let a = 0;
|
||||
let b = last;
|
||||
let c;
|
||||
let distance;
|
||||
while (a < b - 1) {
|
||||
c = (a + b) / 2 | 0;
|
||||
distance = offscreenDistance(c);
|
||||
if (!distance || !c) {
|
||||
break;
|
||||
}
|
||||
const distancePrev = offscreenDistance(c - 1);
|
||||
const distanceNext = c < last ? offscreenDistance(c + 1) : 1e20;
|
||||
if (distancePrev <= distance && distance <= distanceNext) {
|
||||
b = c;
|
||||
} else {
|
||||
a = c;
|
||||
}
|
||||
}
|
||||
while (b && offscreenDistance(b - 1) <= offscreenDistance(b)) {
|
||||
b--;
|
||||
}
|
||||
const cm = editors[b];
|
||||
if (distances[b] > 0) {
|
||||
makeSectionVisible(cm);
|
||||
}
|
||||
return cm;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
function getCodeMirrorThemes() {
|
||||
if (!chrome.runtime.getPackageDirectoryEntry) {
|
||||
const themes = [
|
||||
chrome.i18n.getMessage('defaultTheme'),
|
||||
'3024-day',
|
||||
'3024-night',
|
||||
'abcdef',
|
||||
'ambiance',
|
||||
'ambiance-mobile',
|
||||
'base16-dark',
|
||||
'base16-light',
|
||||
'bespin',
|
||||
'blackboard',
|
||||
'cobalt',
|
||||
'colorforth',
|
||||
'dracula',
|
||||
'duotone-dark',
|
||||
'duotone-light',
|
||||
'eclipse',
|
||||
'elegant',
|
||||
'erlang-dark',
|
||||
'hopscotch',
|
||||
'icecoder',
|
||||
'isotope',
|
||||
'lesser-dark',
|
||||
'liquibyte',
|
||||
'material',
|
||||
'mbo',
|
||||
'mdn-like',
|
||||
'midnight',
|
||||
'monokai',
|
||||
'neat',
|
||||
'neo',
|
||||
'night',
|
||||
'panda-syntax',
|
||||
'paraiso-dark',
|
||||
'paraiso-light',
|
||||
'pastel-on-dark',
|
||||
'railscasts',
|
||||
'rubyblue',
|
||||
'seti',
|
||||
'solarized',
|
||||
'the-matrix',
|
||||
'tomorrow-night-bright',
|
||||
'tomorrow-night-eighties',
|
||||
'ttcn',
|
||||
'twilight',
|
||||
'vibrant-ink',
|
||||
'xq-dark',
|
||||
'xq-light',
|
||||
'yeti',
|
||||
'zenburn',
|
||||
];
|
||||
localStorage.codeMirrorThemes = themes.join(' ');
|
||||
return Promise.resolve(themes);
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
chrome.runtime.getPackageDirectoryEntry(rootDir => {
|
||||
rootDir.getDirectory('vendor/codemirror/theme', {create: false}, themeDir => {
|
||||
themeDir.createReader().readEntries(entries => {
|
||||
const themes = [
|
||||
chrome.i18n.getMessage('defaultTheme')
|
||||
].concat(
|
||||
entries.filter(entry => entry.isFile)
|
||||
.sort((a, b) => (a.name < b.name ? -1 : 1))
|
||||
.map(entry => entry.name.replace(/\.css$/, ''))
|
||||
);
|
||||
localStorage.codeMirrorThemes = themes.join(' ');
|
||||
resolve(themes);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
|
@ -75,20 +75,33 @@ var initColorpicker = () => {
|
|||
spellcheck: false,
|
||||
value: prefs.get('editor.colorpicker.hotkey'),
|
||||
onkeydown(event) {
|
||||
const key = CodeMirror.keyName(event);
|
||||
// ignore: [Shift?] characters, modifiers-only, [Shift?] Esc, Enter, [Shift?] Tab
|
||||
if (key === 'Enter' || key === 'Esc') {
|
||||
$('#help-popup .dismiss').onclick();
|
||||
return;
|
||||
} else if (/^(Space|(Shift-)?(Esc|Tab|[!-~])|(Shift-?|Ctrl-?|Alt-?|Cmd-?)*)$/.test(key)) {
|
||||
this.setCustomValidity('Not allowed');
|
||||
} else {
|
||||
this.setCustomValidity('');
|
||||
prefs.set('editor.colorpicker.hotkey', key);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const key = CodeMirror.keyName(event);
|
||||
switch (key) {
|
||||
case 'Enter':
|
||||
if (this.checkValidity()) {
|
||||
$('#help-popup .dismiss').onclick();
|
||||
}
|
||||
return;
|
||||
case 'Esc':
|
||||
$('#help-popup .dismiss').onclick();
|
||||
return;
|
||||
default:
|
||||
// disallow: [Shift?] characters, modifiers-only, [modifiers?] + Esc, Tab, nav keys
|
||||
if (!key || new RegExp('^(' + [
|
||||
'(Back)?Space',
|
||||
'(Shift-)?.', // a single character
|
||||
'(Shift-?|Ctrl-?|Alt-?|Cmd-?){0,2}(|Esc|Tab|(Page)?(Up|Down)|Left|Right|Home|End|Insert|Delete)',
|
||||
].join('|') + ')$', 'i').test(key)) {
|
||||
this.value = key || this.value;
|
||||
this.setCustomValidity('Not allowed');
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.value = key;
|
||||
this.setCustomValidity('');
|
||||
prefs.set('editor.colorpicker.hotkey', key);
|
||||
},
|
||||
oninput() {
|
||||
// fired on pressing "x" to clear the field
|
||||
|
|
2125
edit/edit.js
2125
edit/edit.js
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
/* global CodeMirror messageBox */
|
||||
/* global editors makeSectionVisible showCodeMirrorPopup showHelp hotkeyRerouter */
|
||||
/* global editors makeSectionVisible showCodeMirrorPopup showHelp */
|
||||
/* global loadScript require CSSLint stylelint */
|
||||
/* global makeLink */
|
||||
'use strict';
|
||||
|
@ -449,10 +449,10 @@ function setupLinterPopup(config) {
|
|||
cm.on('changes', updateButtonState);
|
||||
updateButtonState();
|
||||
|
||||
hotkeyRerouter.setState(false);
|
||||
cm.rerouteHotkeys(false);
|
||||
window.addEventListener('closeHelp', function _() {
|
||||
window.removeEventListener('closeHelp', _);
|
||||
hotkeyRerouter.setState(true);
|
||||
cm.rerouteHotkeys(true);
|
||||
});
|
||||
|
||||
loadScript([
|
||||
|
|
515
edit/sections.js
Normal file
515
edit/sections.js
Normal file
|
@ -0,0 +1,515 @@
|
|||
/*
|
||||
global CodeMirror
|
||||
global editors propertyToCss CssToProperty
|
||||
global onChange indicateCodeChange initHooks setCleanGlobal
|
||||
global fromMozillaFormat maximizeCodeHeight toggleContextMenuDelete
|
||||
global setCleanItem updateTitle updateLintReportIfEnabled renderLintReport
|
||||
global showAppliesToHelp beautify regExpTester setGlobalProgress setCleanSection
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
function initWithSectionStyle({style, codeIsUpdated}) {
|
||||
$('#name').value = style.name || '';
|
||||
$('#enabled').checked = style.enabled !== false;
|
||||
$('#url').href = style.url || '';
|
||||
if (codeIsUpdated !== false) {
|
||||
editors.length = 0;
|
||||
getSections().forEach(div => div.remove());
|
||||
addSections(style.sections.length ? style.sections : [{code: ''}]);
|
||||
initHooks();
|
||||
}
|
||||
setCleanGlobal();
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
function addSections(sections, onAdded = () => {}) {
|
||||
if (addSections.running) {
|
||||
console.error('addSections cannot be re-entered: please report to the developers');
|
||||
// TODO: handle this properly e.g. on update/import
|
||||
return;
|
||||
}
|
||||
addSections.running = true;
|
||||
maximizeCodeHeight.stats = null;
|
||||
// make a shallow copy since we might run asynchronously
|
||||
// and the original array might get modified
|
||||
sections = sections.slice();
|
||||
const t0 = performance.now();
|
||||
const divs = [];
|
||||
let index = 0;
|
||||
|
||||
return new Promise(function run(resolve) {
|
||||
while (index < sections.length) {
|
||||
const div = addSection(null, sections[index]);
|
||||
maximizeCodeHeight(div, index === sections.length - 1);
|
||||
onAdded(div, index);
|
||||
divs.push(div);
|
||||
maybeFocusFirstCM();
|
||||
index++;
|
||||
const elapsed = performance.now() - t0;
|
||||
if (elapsed > 500) {
|
||||
setGlobalProgress(index, sections.length);
|
||||
}
|
||||
if (elapsed > 100) {
|
||||
// after 100ms the sections are added asynchronously
|
||||
setTimeout(run, 0, resolve);
|
||||
return;
|
||||
}
|
||||
}
|
||||
editors.last.state.renderLintReportNow = true;
|
||||
addSections.running = false;
|
||||
setGlobalProgress();
|
||||
resolve(divs);
|
||||
});
|
||||
|
||||
function maybeFocusFirstCM() {
|
||||
const isPageLocked = document.documentElement.style.pointerEvents;
|
||||
if (divs[0] && (isPageLocked ? divs.length === sections.length : index === 0)) {
|
||||
makeSectionVisible(divs[0].CodeMirror);
|
||||
divs[0].CodeMirror.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addSection(event, section) {
|
||||
const div = template.section.cloneNode(true);
|
||||
$('.applies-to-help', div).addEventListener('click', showAppliesToHelp, false);
|
||||
$('.remove-section', div).addEventListener('click', removeSection, false);
|
||||
$('.add-section', div).addEventListener('click', addSection, false);
|
||||
$('.beautify-section', div).addEventListener('click', beautify);
|
||||
|
||||
const code = (section || {}).code || '';
|
||||
|
||||
const appliesTo = $('.applies-to-list', div);
|
||||
let appliesToAdded = false;
|
||||
|
||||
if (section) {
|
||||
for (const i in propertyToCss) {
|
||||
if (section[i]) {
|
||||
section[i].forEach(url => {
|
||||
addAppliesTo(appliesTo, propertyToCss[i], url);
|
||||
appliesToAdded = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!appliesToAdded) {
|
||||
addAppliesTo(appliesTo);
|
||||
}
|
||||
|
||||
appliesTo.addEventListener('change', onChange);
|
||||
appliesTo.addEventListener('input', onChange);
|
||||
|
||||
toggleTestRegExpVisibility();
|
||||
appliesTo.addEventListener('change', toggleTestRegExpVisibility);
|
||||
$('.test-regexp', div).onclick = () => {
|
||||
regExpTester.toggle();
|
||||
regExpTester.update(getRegExps());
|
||||
};
|
||||
|
||||
function getRegExps() {
|
||||
return [...appliesTo.children]
|
||||
.map(item =>
|
||||
!item.matches('.applies-to-everything') &&
|
||||
$('.applies-type', item).value === 'regexp' &&
|
||||
$('.applies-value', item).value.trim()
|
||||
)
|
||||
.filter(item => item);
|
||||
}
|
||||
|
||||
function toggleTestRegExpVisibility() {
|
||||
const show = getRegExps().length > 0;
|
||||
div.classList.toggle('has-regexp', show);
|
||||
appliesTo.oninput = appliesTo.oninput || show && (event => {
|
||||
if (event.target.matches('.applies-value') &&
|
||||
$('.applies-type', event.target.parentElement).value === 'regexp') {
|
||||
regExpTester.update(getRegExps());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const sections = $('#sections');
|
||||
let cm;
|
||||
if (event) {
|
||||
const clickedSection = getSectionForChild(event.target);
|
||||
sections.insertBefore(div, clickedSection.nextElementSibling);
|
||||
const newIndex = getSections().indexOf(clickedSection) + 1;
|
||||
cm = setupCodeMirror(div, code, newIndex);
|
||||
makeSectionVisible(cm);
|
||||
renderLintReport();
|
||||
cm.focus();
|
||||
} else {
|
||||
sections.appendChild(div);
|
||||
cm = setupCodeMirror(div, code);
|
||||
}
|
||||
div.CodeMirror = cm;
|
||||
setCleanSection(div);
|
||||
return div;
|
||||
}
|
||||
|
||||
function addAppliesTo(list, name, value) {
|
||||
const showingEverything = $('.applies-to-everything', list) !== null;
|
||||
// blow away 'Everything' if it's there
|
||||
if (showingEverything) {
|
||||
list.removeChild(list.firstChild);
|
||||
}
|
||||
let e;
|
||||
if (name) {
|
||||
e = template.appliesTo.cloneNode(true);
|
||||
$('[name=applies-type]', e).value = name;
|
||||
$('[name=applies-value]', e).value = value;
|
||||
$('.remove-applies-to', e).addEventListener('click', removeAppliesTo, false);
|
||||
} else if (showingEverything || list.hasChildNodes()) {
|
||||
e = template.appliesTo.cloneNode(true);
|
||||
if (list.hasChildNodes()) {
|
||||
$('[name=applies-type]', e).value = $('li:last-child [name="applies-type"]', list).value;
|
||||
}
|
||||
$('.remove-applies-to', e).addEventListener('click', removeAppliesTo, false);
|
||||
} else {
|
||||
e = template.appliesToEverything.cloneNode(true);
|
||||
}
|
||||
$('.add-applies-to', e).addEventListener('click', function () {
|
||||
addAppliesTo(this.parentNode.parentNode);
|
||||
}, false);
|
||||
list.appendChild(e);
|
||||
}
|
||||
|
||||
function setupCodeMirror(sectionDiv, code, index) {
|
||||
const cm = CodeMirror(wrapper => {
|
||||
$('.code-label', sectionDiv).insertAdjacentElement('afterend', wrapper);
|
||||
}, {
|
||||
value: code,
|
||||
});
|
||||
const wrapper = cm.display.wrapper;
|
||||
|
||||
let onChangeTimer;
|
||||
cm.on('changes', (cm, changes) => {
|
||||
clearTimeout(onChangeTimer);
|
||||
onChangeTimer = setTimeout(indicateCodeChange, 200, cm, changes);
|
||||
});
|
||||
if (prefs.get('editor.autocompleteOnTyping')) {
|
||||
setupAutocomplete(cm);
|
||||
}
|
||||
wrapper.addEventListener('keydown', event => nextPrevEditorOnKeydown(cm, event), true);
|
||||
cm.on('blur', () => {
|
||||
editors.lastActive = cm;
|
||||
cm.rerouteHotkeys(true);
|
||||
setTimeout(() => {
|
||||
wrapper.classList.toggle('CodeMirror-active', wrapper.contains(document.activeElement));
|
||||
});
|
||||
});
|
||||
cm.on('focus', () => {
|
||||
cm.rerouteHotkeys(false);
|
||||
wrapper.classList.add('CodeMirror-active');
|
||||
});
|
||||
cm.on('paste', (cm, event) => {
|
||||
const text = event.clipboardData.getData('text') || '';
|
||||
if (
|
||||
text.includes('@-moz-document') &&
|
||||
text.replace(/\/\*[\s\S]*?\*\//g, '')
|
||||
.match(/@-moz-document[\s\r\n]+(url|url-prefix|domain|regexp)\(/)
|
||||
) {
|
||||
event.preventDefault();
|
||||
fromMozillaFormat();
|
||||
$('#help-popup').codebox.setValue(text);
|
||||
$('#help-popup').codebox.clearHistory();
|
||||
$('#help-popup').codebox.markClean();
|
||||
}
|
||||
if (editors.length === 1) {
|
||||
setTimeout(() => {
|
||||
if (cm.display.sizer.clientHeight > cm.display.wrapper.clientHeight) {
|
||||
maximizeCodeHeight.stats = null;
|
||||
maximizeCodeHeight(cm.getSection(), true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (!FIREFOX) {
|
||||
cm.on('mousedown', (cm, event) => toggleContextMenuDelete.call(cm, event));
|
||||
}
|
||||
|
||||
wrapper.classList.add('resize-grip-enabled');
|
||||
let lastClickTime = 0;
|
||||
const resizeGrip = wrapper.appendChild(template.resizeGrip.cloneNode(true));
|
||||
resizeGrip.onmousedown = event => {
|
||||
if (event.button !== 0) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
if (Date.now() - lastClickTime < 500) {
|
||||
lastClickTime = 0;
|
||||
toggleSectionHeight(cm);
|
||||
return;
|
||||
}
|
||||
lastClickTime = Date.now();
|
||||
const minHeight = cm.defaultTextHeight() +
|
||||
/* .CodeMirror-lines padding */
|
||||
cm.display.lineDiv.offsetParent.offsetTop +
|
||||
/* borders */
|
||||
wrapper.offsetHeight - wrapper.clientHeight;
|
||||
wrapper.style.pointerEvents = 'none';
|
||||
document.body.style.cursor = 's-resize';
|
||||
function resize(e) {
|
||||
const cmPageY = wrapper.getBoundingClientRect().top + window.scrollY;
|
||||
const height = Math.max(minHeight, e.pageY - cmPageY);
|
||||
if (height !== wrapper.clientHeight) {
|
||||
cm.setSize(null, height);
|
||||
}
|
||||
}
|
||||
document.addEventListener('mousemove', resize);
|
||||
document.addEventListener('mouseup', function resizeStop() {
|
||||
document.removeEventListener('mouseup', resizeStop);
|
||||
document.removeEventListener('mousemove', resize);
|
||||
wrapper.style.pointerEvents = '';
|
||||
document.body.style.cursor = '';
|
||||
});
|
||||
};
|
||||
|
||||
editors.splice(index || editors.length, 0, cm);
|
||||
return cm;
|
||||
}
|
||||
|
||||
function indicateCodeChange(cm) {
|
||||
const section = cm.getSection();
|
||||
setCleanItem(section, cm.isClean(section.savedValue));
|
||||
updateTitle();
|
||||
updateLintReportIfEnabled(cm);
|
||||
}
|
||||
|
||||
function setupAutocomplete(cm, enable = true) {
|
||||
const onOff = enable ? 'on' : 'off';
|
||||
cm[onOff]('changes', autocompleteOnTyping);
|
||||
cm[onOff]('pick', autocompletePicked);
|
||||
}
|
||||
|
||||
function autocompleteOnTyping(cm, [info], debounced) {
|
||||
if (
|
||||
cm.state.completionActive ||
|
||||
info.origin && !info.origin.includes('input') ||
|
||||
!info.text.last
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (cm.state.autocompletePicked) {
|
||||
cm.state.autocompletePicked = false;
|
||||
return;
|
||||
}
|
||||
if (!debounced) {
|
||||
debounce(autocompleteOnTyping, 100, cm, [info], true);
|
||||
return;
|
||||
}
|
||||
if (info.text.last.match(/[-a-z!]+$/i)) {
|
||||
cm.state.autocompletePicked = false;
|
||||
cm.options.hintOptions.completeSingle = false;
|
||||
cm.execCommand('autocomplete');
|
||||
setTimeout(() => {
|
||||
cm.options.hintOptions.completeSingle = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function autocompletePicked(cm) {
|
||||
cm.state.autocompletePicked = true;
|
||||
}
|
||||
|
||||
function nextPrevEditorOnKeydown(cm, event) {
|
||||
const key = event.which;
|
||||
if (key < 37 || key > 40 || event.shiftKey || event.altKey || event.metaKey) {
|
||||
return;
|
||||
}
|
||||
const {line, ch} = cm.getCursor();
|
||||
switch (key) {
|
||||
case 37:
|
||||
// arrow Left
|
||||
if (line || ch) {
|
||||
return;
|
||||
}
|
||||
// fallthrough to arrow Up
|
||||
case 38:
|
||||
// arrow Up
|
||||
if (line > 0 || cm === editors[0]) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
cm = CodeMirror.commands.prevEditor.call(cm);
|
||||
cm.setCursor(cm.doc.size - 1, key === 37 ? 1e20 : ch);
|
||||
break;
|
||||
case 39:
|
||||
// arrow Right
|
||||
if (line < cm.doc.size - 1 || ch < cm.getLine(line).length - 1) {
|
||||
return;
|
||||
}
|
||||
// fallthrough to arrow Down
|
||||
case 40:
|
||||
// arrow Down
|
||||
if (line < cm.doc.size - 1 || cm === editors.last) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
cm = CodeMirror.commands.nextEditor.call(cm);
|
||||
cm.setCursor(0, 0);
|
||||
break;
|
||||
}
|
||||
const animation = (cm.getSection().firstElementChild.getAnimations() || [])[0];
|
||||
if (animation) {
|
||||
animation.playbackRate = -1;
|
||||
animation.currentTime = 2000;
|
||||
animation.play();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSectionHeight(cm) {
|
||||
if (cm.state.toggleHeightSaved) {
|
||||
// restore previous size
|
||||
cm.setSize(null, cm.state.toggleHeightSaved);
|
||||
cm.state.toggleHeightSaved = 0;
|
||||
} else {
|
||||
// maximize
|
||||
const wrapper = cm.display.wrapper;
|
||||
const allBounds = $('#sections').getBoundingClientRect();
|
||||
const pageExtrasHeight = allBounds.top + window.scrollY +
|
||||
parseFloat(getComputedStyle($('#sections')).paddingBottom);
|
||||
const sectionExtrasHeight = cm.getSection().clientHeight - wrapper.offsetHeight;
|
||||
cm.state.toggleHeightSaved = wrapper.clientHeight;
|
||||
cm.setSize(null, window.innerHeight - sectionExtrasHeight - pageExtrasHeight);
|
||||
const bounds = cm.getSection().getBoundingClientRect();
|
||||
if (bounds.top < 0 || bounds.bottom > window.innerHeight) {
|
||||
window.scrollBy(0, bounds.top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSectionForChild(e) {
|
||||
return e.closest('#sections > div');
|
||||
}
|
||||
|
||||
function getSections() {
|
||||
return $$('#sections > div');
|
||||
}
|
||||
|
||||
function getSectionsHashes() {
|
||||
const sections = [];
|
||||
getSections().forEach(div => {
|
||||
const meta = {urls: [], urlPrefixes: [], domains: [], regexps: []};
|
||||
for (const li of $('.applies-to-list', div).childNodes) {
|
||||
if (li.className === template.appliesToEverything.className) {
|
||||
return;
|
||||
}
|
||||
const type = $('[name=applies-type]', li).value;
|
||||
const value = $('[name=applies-value]', li).value;
|
||||
if (type && value) {
|
||||
meta[CssToProperty[type]].push(value);
|
||||
}
|
||||
}
|
||||
const code = div.CodeMirror.getValue();
|
||||
if (/^\s*$/.test(code) && Object.keys(meta).length === 0) {
|
||||
return;
|
||||
}
|
||||
meta.code = code;
|
||||
sections.push(meta);
|
||||
});
|
||||
return sections;
|
||||
}
|
||||
|
||||
function removeAppliesTo(event) {
|
||||
const appliesTo = event.target.parentNode;
|
||||
const appliesToList = appliesTo.parentNode;
|
||||
removeAreaAndSetDirty(appliesTo);
|
||||
if (!appliesToList.hasChildNodes()) {
|
||||
addAppliesTo(appliesToList);
|
||||
}
|
||||
}
|
||||
|
||||
function removeSection(event) {
|
||||
const section = getSectionForChild(event.target);
|
||||
const cm = section.CodeMirror;
|
||||
removeAreaAndSetDirty(section);
|
||||
editors.splice(editors.indexOf(cm), 1);
|
||||
renderLintReport();
|
||||
}
|
||||
|
||||
function removeAreaAndSetDirty(area) {
|
||||
const contributors = $$('.style-contributor', area);
|
||||
if (!contributors.length) {
|
||||
setCleanItem(area, false);
|
||||
}
|
||||
contributors.some(node => {
|
||||
if (node.savedValue) {
|
||||
// it's a saved section, so make it dirty and stop the enumeration
|
||||
setCleanItem(area, false);
|
||||
return true;
|
||||
} else {
|
||||
// it's an empty section, so undirty the applies-to items,
|
||||
// otherwise orphaned ids would keep the style dirty
|
||||
setCleanItem(node, true);
|
||||
}
|
||||
});
|
||||
updateTitle();
|
||||
area.parentNode.removeChild(area);
|
||||
}
|
||||
|
||||
function makeSectionVisible(cm) {
|
||||
const section = cm.getSection();
|
||||
const bounds = section.getBoundingClientRect();
|
||||
if (
|
||||
(bounds.bottom > window.innerHeight && bounds.top > 0) ||
|
||||
(bounds.top < 0 && bounds.bottom < window.innerHeight)
|
||||
) {
|
||||
if (bounds.top < 0) {
|
||||
window.scrollBy(0, bounds.top - 1);
|
||||
} else {
|
||||
window.scrollBy(0, bounds.bottom - window.innerHeight + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function maximizeCodeHeight(sectionDiv, isLast) {
|
||||
const cm = sectionDiv.CodeMirror;
|
||||
const stats = maximizeCodeHeight.stats = maximizeCodeHeight.stats || {totalHeight: 0, deltas: []};
|
||||
if (!stats.cmActualHeight) {
|
||||
stats.cmActualHeight = getComputedHeight(cm.display.wrapper);
|
||||
}
|
||||
if (!stats.sectionMarginTop) {
|
||||
stats.sectionMarginTop = parseFloat(getComputedStyle(sectionDiv).marginTop);
|
||||
}
|
||||
const sectionTop = sectionDiv.getBoundingClientRect().top - stats.sectionMarginTop;
|
||||
if (!stats.firstSectionTop) {
|
||||
stats.firstSectionTop = sectionTop;
|
||||
}
|
||||
const extrasHeight = getComputedHeight(sectionDiv) - stats.cmActualHeight;
|
||||
const cmMaxHeight = window.innerHeight - extrasHeight - sectionTop - stats.sectionMarginTop;
|
||||
const cmDesiredHeight = cm.display.sizer.clientHeight + 2 * cm.defaultTextHeight();
|
||||
const cmGrantableHeight = Math.max(stats.cmActualHeight, Math.min(cmMaxHeight, cmDesiredHeight));
|
||||
stats.deltas.push(cmGrantableHeight - stats.cmActualHeight);
|
||||
stats.totalHeight += cmGrantableHeight + extrasHeight;
|
||||
if (!isLast) {
|
||||
return;
|
||||
}
|
||||
stats.totalHeight += stats.firstSectionTop;
|
||||
if (stats.totalHeight <= window.innerHeight) {
|
||||
editors.forEach((cm, index) => {
|
||||
cm.setSize(null, stats.deltas[index] + stats.cmActualHeight);
|
||||
});
|
||||
return;
|
||||
}
|
||||
// scale heights to fill the gap between last section and bottom edge of the window
|
||||
const sections = $('#sections');
|
||||
const available = window.innerHeight - sections.getBoundingClientRect().bottom -
|
||||
parseFloat(getComputedStyle(sections).marginBottom);
|
||||
if (available <= 0) {
|
||||
return;
|
||||
}
|
||||
const totalDelta = stats.deltas.reduce((sum, d) => sum + d, 0);
|
||||
const q = available / totalDelta;
|
||||
const baseHeight = stats.cmActualHeight - stats.sectionMarginTop;
|
||||
stats.deltas.forEach((delta, index) => {
|
||||
editors[index].setSize(null, baseHeight + Math.floor(q * delta));
|
||||
});
|
||||
|
||||
function getComputedHeight(el) {
|
||||
const compStyle = getComputedStyle(el);
|
||||
return el.getBoundingClientRect().height +
|
||||
parseFloat(compStyle.marginTop) + parseFloat(compStyle.marginBottom);
|
||||
}
|
||||
}
|
109
edit/show-keymap-help.js
Normal file
109
edit/show-keymap-help.js
Normal file
|
@ -0,0 +1,109 @@
|
|||
/* global CodeMirror showHelp */
|
||||
'use strict';
|
||||
|
||||
onDOMready().then(() => {
|
||||
$('#keyMap-help').addEventListener('click', showKeyMapHelp);
|
||||
});
|
||||
|
||||
function showKeyMapHelp() {
|
||||
const keyMap = mergeKeyMaps({}, prefs.get('editor.keyMap'), CodeMirror.defaults.extraKeys);
|
||||
const keyMapSorted = Object.keys(keyMap)
|
||||
.map(key => ({key, cmd: keyMap[key]}))
|
||||
.concat([{key: 'Shift-Ctrl-Wheel', cmd: 'scrollWindow'}])
|
||||
.sort((a, b) => (a.cmd < b.cmd || (a.cmd === b.cmd && a.key < b.key) ? -1 : 1));
|
||||
const table = template.keymapHelp.cloneNode(true);
|
||||
const tBody = table.tBodies[0];
|
||||
const row = tBody.rows[0];
|
||||
const cellA = row.children[0];
|
||||
const cellB = row.children[1];
|
||||
tBody.textContent = '';
|
||||
for (const {key, cmd} of keyMapSorted) {
|
||||
cellA.textContent = key;
|
||||
cellB.textContent = cmd;
|
||||
tBody.appendChild(row.cloneNode(true));
|
||||
}
|
||||
|
||||
showHelp(t('cm_keyMap') + ': ' + prefs.get('editor.keyMap'), table);
|
||||
|
||||
const inputs = $$('input', table);
|
||||
inputs[0].addEventListener('keydown', hotkeyHandler);
|
||||
inputs[1].focus();
|
||||
|
||||
table.oninput = filterTable;
|
||||
|
||||
function hotkeyHandler(event) {
|
||||
const keyName = CodeMirror.keyName(event);
|
||||
if (keyName === 'Esc' || keyName === 'Tab' || keyName === 'Shift-Tab') {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
// normalize order of modifiers,
|
||||
// for modifier-only keys ('Ctrl-Shift') a dummy main key has to be temporarily added
|
||||
const keyMap = {};
|
||||
keyMap[keyName.replace(/(Shift|Ctrl|Alt|Cmd)$/, '$&-dummy')] = '';
|
||||
const normalizedKey = Object.keys(CodeMirror.normalizeKeyMap(keyMap))[0];
|
||||
this.value = normalizedKey.replace('-dummy', '');
|
||||
filterTable(event);
|
||||
}
|
||||
|
||||
function filterTable(event) {
|
||||
const input = event.target;
|
||||
const col = input.parentNode.cellIndex;
|
||||
inputs[1 - col].value = '';
|
||||
for (const row of tBody.rows) {
|
||||
const cell = row.children[col];
|
||||
const text = cell.textContent;
|
||||
const query = stringAsRegExp(input.value, 'gi');
|
||||
const test = query.test(text);
|
||||
row.style.display = input.value && test === false ? 'none' : '';
|
||||
if (input.value && test) {
|
||||
cell.textContent = '';
|
||||
let offset = 0;
|
||||
text.replace(query, (match, index) => {
|
||||
if (index > offset) {
|
||||
cell.appendChild(document.createTextNode(text.substring(offset, index)));
|
||||
}
|
||||
cell.appendChild($element({tag: 'mark', textContent: match}));
|
||||
offset = index + match.length;
|
||||
});
|
||||
if (offset + 1 !== text.length) {
|
||||
cell.appendChild(document.createTextNode(text.substring(offset)));
|
||||
}
|
||||
} else {
|
||||
cell.textContent = text;
|
||||
}
|
||||
// clear highlight from the other column
|
||||
const otherCell = row.children[1 - col];
|
||||
if (otherCell.children.length) {
|
||||
const text = otherCell.textContent;
|
||||
otherCell.textContent = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
function mergeKeyMaps(merged, ...more) {
|
||||
more.forEach(keyMap => {
|
||||
if (typeof keyMap === 'string') {
|
||||
keyMap = CodeMirror.keyMap[keyMap];
|
||||
}
|
||||
Object.keys(keyMap).forEach(key => {
|
||||
let cmd = keyMap[key];
|
||||
// filter out '...', 'attach', etc. (hotkeys start with an uppercase letter)
|
||||
if (!merged[key] && !key.match(/^[a-z]/) && cmd !== '...') {
|
||||
if (typeof cmd === 'function') {
|
||||
// for 'emacs' keymap: provide at least something meaningful (hotkeys and the function body)
|
||||
// for 'vim*' keymaps: almost nothing as it doesn't rely on CM keymap mechanism
|
||||
cmd = cmd.toString().replace(/^function.*?\{[\s\r\n]*([\s\S]+?)[\s\r\n]*\}$/, '$1');
|
||||
merged[key] = cmd.length <= 200 ? cmd : cmd.substr(0, 200) + '...';
|
||||
} else {
|
||||
merged[key] = cmd;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (keyMap.fallthrough) {
|
||||
merged = mergeKeyMaps(merged, keyMap.fallthrough);
|
||||
}
|
||||
});
|
||||
return merged;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
/* global CodeMirror dirtyReporter initLint beautify showKeyMapHelp */
|
||||
/* global CodeMirror dirtyReporter initLint */
|
||||
/* global showToggleStyleHelp goBackToManage updateLintReportIfEnabled */
|
||||
/* global hotkeyRerouter setupAutocomplete */
|
||||
/* global editors linterConfig updateLinter regExpTester mozParser */
|
||||
/* global makeLink createAppliesToLineWidget messageBox */
|
||||
'use strict';
|
||||
|
@ -124,10 +123,7 @@ function createSourceEditor(style) {
|
|||
|
||||
function initHooks() {
|
||||
$('#save-button').onclick = save;
|
||||
$('#beautify').onclick = beautify;
|
||||
$('#keyMap-help').onclick = showKeyMapHelp;
|
||||
$('#toggle-style-help').onclick = showToggleStyleHelp;
|
||||
$('#cancel-button').onclick = goBackToManage;
|
||||
|
||||
$('#enabled').onchange = function () {
|
||||
const value = this.checked;
|
||||
|
@ -140,12 +136,13 @@ function createSourceEditor(style) {
|
|||
updateLintReportIfEnabled(cm);
|
||||
});
|
||||
|
||||
cm.on('focus', () => hotkeyRerouter.setState(false));
|
||||
cm.on('blur', () => hotkeyRerouter.setState(true));
|
||||
cm.on('focus', () => cm.rerouteHotkeys(false));
|
||||
cm.on('blur', () => cm.rerouteHotkeys(true));
|
||||
|
||||
//if (prefs.get('editor.autocompleteOnTyping')) {
|
||||
// setupAutocomplete(cm);
|
||||
//}
|
||||
CodeMirror.commands.prevEditor = cm => nextPrevMozDocument(cm, -1);
|
||||
CodeMirror.commands.nextEditor = cm => nextPrevMozDocument(cm, 1);
|
||||
CodeMirror.commands.toggleStyle = toggleStyle;
|
||||
CodeMirror.commands.save = save;
|
||||
}
|
||||
|
||||
function updateMeta() {
|
||||
|
@ -277,6 +274,70 @@ function createSourceEditor(style) {
|
|||
return dirty.isDirty() || hadBeenSaved;
|
||||
}
|
||||
|
||||
function nextPrevMozDocument(cm, dir) {
|
||||
const MOZ_DOC = '@-moz-document';
|
||||
const cursor = cm.getCursor();
|
||||
const usePrevLine = dir < 0 && cursor.ch <= MOZ_DOC.length;
|
||||
let line = cursor.line + (usePrevLine ? -1 : 0);
|
||||
let start = usePrevLine ? 1e9 : cursor.ch + (dir > 0 ? 1 : -MOZ_DOC.length);
|
||||
let found;
|
||||
if (dir > 0) {
|
||||
cm.doc.iter(cursor.line, cm.doc.size, goFind);
|
||||
if (!found && cursor.line > 0) {
|
||||
line = 0;
|
||||
cm.doc.iter(0, cursor.line + 1, goFind);
|
||||
}
|
||||
} else {
|
||||
let handle, parentLines;
|
||||
let passesRemain = line < cm.doc.size - 1 ? 2 : 1;
|
||||
let stopAtLine = 0;
|
||||
while (passesRemain--) {
|
||||
let indexInParent = 0;
|
||||
while (line >= stopAtLine) {
|
||||
if (!indexInParent--) {
|
||||
handle = cm.getLineHandle(line);
|
||||
parentLines = handle.parent.lines;
|
||||
indexInParent = parentLines.indexOf(handle);
|
||||
} else {
|
||||
handle = parentLines[indexInParent];
|
||||
}
|
||||
if (goFind(handle)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
line = cm.doc.size - 1;
|
||||
stopAtLine = cursor.line;
|
||||
}
|
||||
}
|
||||
function goFind({text}) {
|
||||
// use the initial 'start' on cursor row...
|
||||
let ch = start;
|
||||
// ...and reset it for the rest
|
||||
start = dir > 0 ? 0 : 1e9;
|
||||
while (true) {
|
||||
// indexOf is 1000x faster than toLowerCase().indexOf() so we're trying it first
|
||||
ch = dir > 0 ? text.indexOf('@-', ch) : text.lastIndexOf('@-', ch);
|
||||
if (ch < 0) {
|
||||
line += dir;
|
||||
return;
|
||||
}
|
||||
if (text.substr(ch, MOZ_DOC.length).toLowerCase() === MOZ_DOC &&
|
||||
cm.getTokenTypeAt({line, ch: ch + 1}) === 'def') {
|
||||
break;
|
||||
}
|
||||
ch += dir * 3;
|
||||
}
|
||||
cm.setCursor(line, ch);
|
||||
if (cm.cursorCoords().bottom > cm.display.scroller.clientHeight - 100) {
|
||||
const margin = Math.min(100, cm.display.scroller.clientHeight / 4);
|
||||
line += prefs.get('editor.appliesToLineWidget') ? 1 : 0;
|
||||
cm.scrollIntoView({line, ch}, margin);
|
||||
}
|
||||
found = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
replaceStyle,
|
||||
save,
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
|
||||
$('.header').classList.add('meta-init');
|
||||
$('.header').classList.remove('meta-init-error');
|
||||
setTimeout(() => $('.lds-spinner') && $('.lds-spinner').remove(), 1000);
|
||||
setTimeout(() => $.remove('.lds-spinner'), 1000);
|
||||
|
||||
showError('');
|
||||
requestAnimationFrame(adjustCodeHeight);
|
||||
|
@ -195,8 +195,7 @@
|
|||
function install(style) {
|
||||
installed = style;
|
||||
|
||||
$$('.warning')
|
||||
.forEach(el => el.remove());
|
||||
$$.remove('.warning');
|
||||
$('button.install').disabled = true;
|
||||
$('button.install').classList.add('installed');
|
||||
$('h2.installed').classList.add('active');
|
||||
|
|
18
js/dom.js
18
js/dom.js
|
@ -11,6 +11,19 @@ for (const type of [NodeList, NamedNodeMap, HTMLCollection, HTMLAllCollection])
|
|||
}
|
||||
}
|
||||
|
||||
$.remove = (selector, base = document) => {
|
||||
const el = selector && typeof selector === 'string' ? $(selector, base) : selector;
|
||||
if (el) {
|
||||
el.remove();
|
||||
}
|
||||
};
|
||||
|
||||
$$.remove = (selector, base = document) => {
|
||||
for (const el of base.querySelectorAll(selector)) {
|
||||
el.remove();
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
// display a full text tooltip on buttons with ellipsis overflow and no inherent title
|
||||
const addTooltipsToEllipsized = () => {
|
||||
|
@ -41,10 +54,7 @@ for (const type of [NodeList, NamedNodeMap, HTMLCollection, HTMLAllCollection])
|
|||
}
|
||||
|
||||
onDOMready().then(() => {
|
||||
const el = $('#firefox-transitions-bug-suppressor');
|
||||
if (el) {
|
||||
el.remove();
|
||||
}
|
||||
$.remove('#firefox-transitions-bug-suppressor');
|
||||
});
|
||||
|
||||
if (!chrome.app && chrome.windows) {
|
||||
|
|
|
@ -17,6 +17,7 @@ if (!CHROME && !chrome.browserAction.openPopup) {
|
|||
FIREFOX = 50;
|
||||
browser.runtime.getBrowserInfo().then(info => {
|
||||
FIREFOX = parseFloat(info.version);
|
||||
document.documentElement.classList.toggle('moz-appearance-bug', FIREFOX && FIREFOX < 54);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -61,6 +62,7 @@ if (BG && !BG.getStyles && BG !== window) {
|
|||
}
|
||||
if (!BG || BG !== window) {
|
||||
document.documentElement.classList.toggle('firefox', FIREFOX);
|
||||
document.documentElement.classList.toggle('moz-appearance-bug', FIREFOX && FIREFOX < 54);
|
||||
document.documentElement.classList.toggle('opera', OPERA);
|
||||
// TODO: remove once our manifest's minimum_chrome_version is 50+
|
||||
// Chrome 49 doesn't report own extension pages in webNavigation apparently
|
||||
|
@ -226,7 +228,7 @@ function openURL({url, index, openerTabId, currentWindow = true}) {
|
|||
}
|
||||
getActiveTab().then(tab => {
|
||||
const chromeInIncognito = tab && tab.incognito && url.startsWith('chrome');
|
||||
if (tab && tab.url === 'chrome://newtab/' && !chromeInIncognito) {
|
||||
if (tab && (tab.url === 'chrome://newtab/' || tab.url === 'about:newtab') && !chromeInIncognito) {
|
||||
// update current NTP, except for chrome:// or chrome-extension:// in incognito
|
||||
chrome.tabs.update({url}, resolve);
|
||||
} else {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<style id="firefox-transitions-bug-suppressor">
|
||||
/* restrict to FF */
|
||||
@-moz-document url-prefix("") {
|
||||
@supports (-moz-appearance:none) {
|
||||
/* increased specificity to override sane selectors in user styles */
|
||||
html#stylus.firefox #stylus-manage #header * {
|
||||
transition: none !important;
|
||||
|
|
|
@ -79,7 +79,7 @@ select {
|
|||
}
|
||||
|
||||
label.nobreak input {
|
||||
vertical-align: middle;
|
||||
vertical-align: sub;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -972,3 +972,12 @@ fieldset select {
|
|||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (-moz-appearance:none) {
|
||||
|
||||
/* fixes for Firefox quirks */
|
||||
|
||||
#newStyleAsUsercss-wrapper svg {
|
||||
margin-top: -2px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Stylus",
|
||||
"version": "1.1.6.3",
|
||||
"version": "1.1.7",
|
||||
"minimum_chrome_version": "49",
|
||||
"description": "__MSG_description__",
|
||||
"homepage_url": "http://add0n.com/stylus.html",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<style id="firefox-transitions-bug-suppressor">
|
||||
/* restrict to FF */
|
||||
@-moz-document url-prefix("") {
|
||||
@supports (-moz-appearance:none) {
|
||||
/* increased specificity to override sane selectors in user styles */
|
||||
html#stylus.firefox #options *, #stylus #notes * {
|
||||
transition: none !important;
|
||||
|
|
47
popup.html
47
popup.html
|
@ -8,7 +8,7 @@
|
|||
|
||||
<style id="firefox-transitions-bug-suppressor">
|
||||
/* restrict to FF */
|
||||
@-moz-document url-prefix("") {
|
||||
@supports (-moz-appearance:none) {
|
||||
/* increased specificity to override sane selectors in user styles */
|
||||
html#stylus.firefox #stylus-popup #actions * {
|
||||
transition: none !important;
|
||||
|
@ -24,25 +24,27 @@
|
|||
|
||||
<template data-id="style">
|
||||
<div class="entry">
|
||||
<div class="left-gutter">
|
||||
<input class="checker" type="checkbox">
|
||||
</div>
|
||||
<div class="main-controls">
|
||||
<label class="style-name"></label>
|
||||
<div class="actions">
|
||||
<a href="#" class="enable" i18n-text="enableStyleLabel"></a>
|
||||
<a href="#" class="disable" i18n-text="disableStyleLabel"></a>
|
||||
<a class="style-edit-link" href="edit.html?id=" i18n-title="editStyleLabel">
|
||||
<svg class="svg-icon edit" viewBox="0 0 14 16">
|
||||
<path fill-rule="evenodd" d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="#" class="delete" i18n-title="deleteStyleLabel">
|
||||
<svg class="svg-icon remove" viewBox="0 0 14 16">
|
||||
<path fill-rule="evenodd" d="M11 2H9c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1H2c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1v9c0 .55.45 1 1 1h7c.55 0 1-.45 1-1V5c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm-1 12H3V5h1v8h1V5h1v8h1V5h1v8h1V5h1v9zm1-10H2V3h9v1z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<label class="style-name">
|
||||
<input class="checker" type="checkbox">
|
||||
<svg class="svg-icon checked" viewBox="0 0 1000 1000">
|
||||
<path fill-rule="evenodd" d="M983.2,184.3L853,69.8c-4-3.5-9.3-5.3-14.5-5c-5.3,0.4-10.3,2.8-13.8,6.8L352.3,609.2L184.4,386.9c-3.2-4.2-8-7-13.2-7.8c-5.3-0.8-10.6,0.6-14.9,3.9L18,487.5c-8.8,6.7-10.6,19.3-3.9,28.1L325,927.2c3.6,4.8,9.3,7.7,15.3,8c0.2,0,0.5,0,0.7,0c5.8,0,11.3-2.5,15.1-6.8L985,212.6C992.3,204.3,991.5,191.6,983.2,184.3z"/>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="#" class="enable" i18n-text="enableStyleLabel"></a>
|
||||
<a href="#" class="disable" i18n-text="disableStyleLabel"></a>
|
||||
<a class="style-edit-link" href="edit.html?id=" i18n-title="editStyleLabel">
|
||||
<svg class="svg-icon edit" viewBox="0 0 14 16">
|
||||
<path fill-rule="evenodd" d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="#" class="delete" i18n-title="deleteStyleLabel">
|
||||
<svg class="svg-icon remove" viewBox="0 0 14 16">
|
||||
<path fill-rule="evenodd" d="M11 2H9c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1H2c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1v9c0 .55.45 1 1 1h7c.55 0 1-.45 1-1V5c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm-1 12H3V5h1v8h1V5h1v8h1V5h1v8h1V5h1v9zm1-10H2V3h9v1z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -135,10 +137,11 @@
|
|||
|
||||
<div class="actions">
|
||||
<div id="disable-all-wrapper">
|
||||
<div class="left-gutter">
|
||||
<input id="disableAll" type="checkbox">
|
||||
</div>
|
||||
<div class="main-controls">
|
||||
<input id="disableAll" type="checkbox">
|
||||
<svg class="svg-icon checked" viewBox="0 0 1000 1000">
|
||||
<path fill-rule="evenodd" d="M983.2,184.3L853,69.8c-4-3.5-9.3-5.3-14.5-5c-5.3,0.4-10.3,2.8-13.8,6.8L352.3,609.2L184.4,386.9c-3.2-4.2-8-7-13.2-7.8c-5.3-0.8-10.6,0.6-14.9,3.9L18,487.5c-8.8,6.7-10.6,19.3-3.9,28.1L325,927.2c3.6,4.8,9.3,7.7,15.3,8c0.2,0,0.5,0,0.7,0c5.8,0,11.3-2.5,15.1-6.8L985,212.6C992.3,204.3,991.5,191.6,983.2,184.3z"/>
|
||||
</svg>
|
||||
<label id="disableAll-label" for="disableAll" i18n-text="disableAllStyles"></label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -131,7 +131,7 @@ window.addEventListener('showStyles:done', function _() {
|
|||
const height = 4 +
|
||||
container.firstElementChild.scrollHeight +
|
||||
container.lastElementChild.scrollHeight +
|
||||
parseFloat(getComputedStyle(container.firstElementChild).paddingBottom) * 4;
|
||||
parseFloat(getComputedStyle(container.lastElementChild).paddingBottom);
|
||||
if (height > document.body.clientHeight) {
|
||||
document.body.style.height = height + 'px';
|
||||
}
|
||||
|
|
200
popup/popup.css
200
popup/popup.css
|
@ -17,36 +17,149 @@ body {
|
|||
}
|
||||
|
||||
body > div:not(#installed) {
|
||||
margin-left: 0.75em;
|
||||
margin-right: 0.75em;
|
||||
margin-left: 9px;
|
||||
margin-right: 9px;
|
||||
}
|
||||
|
||||
.firefox .chromium-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
/* there's a bug in FF 52 ESR so until we find a better workaround we won't style checkboxes in FF */
|
||||
html.moz-appearance-bug .svg-icon.checked {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html.moz-appearance-bug input[type="checkbox"] {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
html.moz-appearance-bug #disableAll {
|
||||
left: -1px;
|
||||
}
|
||||
|
||||
html.moz-appearance-bug #disableAll-label {
|
||||
padding-left: 16px !important;
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) .svg-icon.checked {
|
||||
position: absolute;
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
display: none;
|
||||
fill: #000;
|
||||
margin: 2px 0 0 2px;
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) input[type="checkbox"]:checked + .svg-icon.checked {
|
||||
display: inline-flex;
|
||||
transition: fill .25s;
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) input[type="checkbox"] {
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
border: 1px solid hsl(0, 0%, 46%);
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
display: inline-flex;
|
||||
border-radius: 2px;
|
||||
background-color: hsl(0, 0%, 94%);
|
||||
outline: none;
|
||||
margin: 0;
|
||||
transition: background-color .25s, border-color .25s;
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) input[type="checkbox"]:checked:hover,
|
||||
html:not(.moz-appearance-bug) .style-name:hover input[type="checkbox"]:checked {
|
||||
border-color: hsl(0, 0%, 32%);
|
||||
background-color: hsl(0, 0%, 82%);
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) input[type="checkbox"]:hover,
|
||||
html:not(.moz-appearance-bug) .style-name:hover input[type="checkbox"],
|
||||
html:not(.moz-appearance-bug) .entry.disabled .style-name:hover input[type="checkbox"] {
|
||||
border-color: hsl(0, 0%, 32%);
|
||||
background-color: hsl(0, 0%, 82%);
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) #installed.disabled + .actions #disableAll:checked + .svg-icon.checked {
|
||||
fill: hsl(0, 68%, 42%);
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) #installed.disabled + .actions #disableAll:checked {
|
||||
border-color: hsl(0, 68%, 50%);
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) #installed.disabled + .actions #disableAll:checked:hover + .svg-icon.checked {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) #disableAll:hover {
|
||||
border-color: hsl(0, 68%, 50%);
|
||||
background-color: hsl(20, 70%, 75%);
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) #disableAll:hover + .svg-icon + label {
|
||||
color: hsl(0, 68%, 42%);
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) #installed.disabled + .actions #disableAll:checked:hover {
|
||||
border-color: hsl(0, 50%, 56%);
|
||||
background-color: hsl(0, 50%, 56%);
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) .style-name .checker,
|
||||
html:not(.moz-appearance-bug) .style-name .svg-icon.checked {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 9px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
html:not(.moz-appearance-bug) #disable-all-wrapper .main-controls .svg-icon.checked {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
label {
|
||||
transition: color .25s;
|
||||
}
|
||||
|
||||
#disable-all-wrapper {
|
||||
padding: 0.3em 0 0.6em;
|
||||
}
|
||||
|
||||
#disable-all-wrapper .main-controls {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#disable-all-wrapper .main-controls label {
|
||||
font-size: 12px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
#no-styles {
|
||||
font-style: italic;
|
||||
margin: 0 .75em;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
#no-styles:before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.checker {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.style-name {
|
||||
cursor: default;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
transition: color .5s;
|
||||
|
@ -57,16 +170,8 @@ a:hover {
|
|||
color: #666;
|
||||
}
|
||||
|
||||
.left-gutter {
|
||||
display: table-cell;
|
||||
width: 16px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.left-gutter input {
|
||||
margin-bottom: 1px;
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
.actions > .main-controls {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.main-controls {
|
||||
|
@ -110,10 +215,46 @@ body.blocked > DIV {
|
|||
.entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px 0.75em;
|
||||
height: 26px;
|
||||
padding: 0 14px 0 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
html[style] .entry {
|
||||
padding: 0 16px 0 0;
|
||||
}
|
||||
|
||||
html[style] .entry:nth-child(-n+10):before,
|
||||
html[style] .entry:nth-child(10):before {
|
||||
right: 7px;
|
||||
}
|
||||
|
||||
.entry .actions {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.style-name {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
line-height: 28px;
|
||||
cursor: default;
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
padding-left: 26px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.entry .main-controls {
|
||||
height: 100%;
|
||||
display: inline-flex;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.entry:nth-child(even) {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
@ -142,20 +283,6 @@ body.blocked > DIV {
|
|||
padding: 0 1px 0;
|
||||
}
|
||||
|
||||
.entry .main-controls {
|
||||
display: flex;
|
||||
width: calc(100% - 20px);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.entry .main-controls label {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.not-applied .checker,
|
||||
.not-applied .style-name,
|
||||
.not-applied .actions > * {
|
||||
|
@ -255,8 +382,7 @@ body > .actions {
|
|||
}
|
||||
|
||||
body.blocked #installed > *,
|
||||
body.blocked .actions > .main-controls,
|
||||
body.blocked .actions > .left-gutter {
|
||||
body.blocked .actions > .main-controls {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,18 +105,20 @@ function initPopup(url) {
|
|||
installed);
|
||||
}
|
||||
|
||||
$('#open-search-link').onclick = handleEvent.openURLandHide;
|
||||
$('#open-search-link').href +=
|
||||
url.startsWith(location.protocol) ?
|
||||
'?search_terms=Stylus' :
|
||||
'all/' + encodeURIComponent(url.startsWith('file:') ? 'file:' : url);
|
||||
|
||||
if (!url) {
|
||||
document.body.classList.add('blocked');
|
||||
document.body.insertBefore(template.unavailableInfo, document.body.firstChild);
|
||||
return;
|
||||
}
|
||||
|
||||
const u = tryCatch(() => new URL(url));
|
||||
$('#open-search-link').onclick = handleEvent.openURLandHide;
|
||||
$('#open-search-link').href +=
|
||||
!u ? '' :
|
||||
u.protocol === 'file:' ? 'file:' :
|
||||
u.protocol === location.protocol ? '?search_terms=Stylus' :
|
||||
u.hostname.replace(/^www\.|(\.com?)?\.\w+$/g, '').split('.').pop();
|
||||
|
||||
getActiveTab().then(function ping(tab, retryCountdown = 10) {
|
||||
sendMessage({tabId: tab.id, method: 'ping', frameId: 0}, pong => {
|
||||
if (pong) {
|
||||
|
@ -348,7 +350,7 @@ Object.assign(handleEvent, {
|
|||
indicator(event) {
|
||||
const entry = handleEvent.getClickedStyleElement(event);
|
||||
const info = template.regexpProblemExplanation.cloneNode(true);
|
||||
$$('#' + info.id).forEach(el => el.remove());
|
||||
$.remove('#' + info.id);
|
||||
$$('a', info).forEach(el => (el.onclick = handleEvent.openURLandHide));
|
||||
$$('button', info).forEach(el => (el.onclick = handleEvent.closeExplanation));
|
||||
entry.appendChild(info);
|
||||
|
@ -420,14 +422,14 @@ function handleUpdate(style) {
|
|||
// Add an entry when a new style for the current url is installed
|
||||
if (tabURL && BG.getApplicableSections({style, matchUrl: tabURL, stopOnFirst: true}).length) {
|
||||
document.body.classList.remove('blocked');
|
||||
$$('.blocked-info, #no-styles').forEach(el => el.remove());
|
||||
$$.remove('.blocked-info, #no-styles');
|
||||
createStyleElement({style});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleDelete(id) {
|
||||
$$(ENTRY_ID_PREFIX + id).forEach(el => el.remove());
|
||||
$.remove(ENTRY_ID_PREFIX + id);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -197,6 +197,12 @@
|
|||
$formatChangeButton.title = opt.tooltipForSwitcher || '';
|
||||
opt.hideDelay = Math.max(0, opt.hideDelay) || 2000;
|
||||
|
||||
$root.classList.add(CSS_PREFIX + 'theme-' +
|
||||
(opt.theme === 'dark' || opt.theme === 'light' ?
|
||||
opt.theme :
|
||||
guessTheme()));
|
||||
document.body.appendChild($root);
|
||||
|
||||
if (!isNaN(options.left) && !isNaN(options.top)) {
|
||||
$root.style = `
|
||||
display: block;
|
||||
|
@ -205,12 +211,6 @@
|
|||
reposition();
|
||||
}
|
||||
|
||||
$root.classList.add(CSS_PREFIX + 'theme-' +
|
||||
(opt.theme === 'dark' || opt.theme === 'light' ?
|
||||
opt.theme :
|
||||
guessTheme()));
|
||||
document.body.appendChild($root);
|
||||
|
||||
shown = true;
|
||||
|
||||
registerEvents();
|
||||
|
|
Loading…
Reference in New Issue
Block a user