Merge branch 'master' into dev-color-scheme
This commit is contained in:
commit
72488cf099
20
.github/workflows/ci.yml
vendored
Normal file
20
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
name: ci
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
node: ['10', '12', '14']
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: npm install
|
||||
- run: npm test
|
|
@ -1277,6 +1277,10 @@
|
|||
"message": "Code formatieren",
|
||||
"description": "Label for the CSS-beautifier button on the edit style page"
|
||||
},
|
||||
"styleBeautifyHint": {
|
||||
"message": "Hinweis: Mache einen Rechtsklick auf \"Code formatieren\" oder nutze das weiter unten definierte Tastenkürzel, um den Code zu formatieren ohne dieses Fenster anzuzeigen.",
|
||||
"description": "Hint shown inside the CSS-beautifier panel"
|
||||
},
|
||||
"styleBeautifyIndentConditional": {
|
||||
"message": "Rücke @media / @supports ein",
|
||||
"description": "CSS-beautifier option"
|
||||
|
|
|
@ -1297,6 +1297,10 @@
|
|||
"message": "Beautify",
|
||||
"description": "Label for the CSS-beautifier button on the edit style page"
|
||||
},
|
||||
"styleBeautifyHint": {
|
||||
"message": "Hint: right-click the “Beautify” button or use the keyboard shortcut defined below to beautify without showing this panel",
|
||||
"description": "Hint shown inside the CSS-beautifier panel"
|
||||
},
|
||||
"styleBeautifyIndentConditional": {
|
||||
"message": "Indent @media, @supports",
|
||||
"description": "CSS-beautifier option"
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
"description": ""
|
||||
},
|
||||
"checkAllUpdates": {
|
||||
"message": "Rechercher des mises à jour pour tous les styles",
|
||||
"message": "Rechercher des mises à jour",
|
||||
"description": "Label for the button to check all styles for updates"
|
||||
},
|
||||
"checkAllUpdatesForce": {
|
||||
|
@ -101,7 +101,7 @@
|
|||
"description": "Label for the button to apply all detected updates"
|
||||
},
|
||||
"checkForUpdate": {
|
||||
"message": "Rechercher des mises à jour",
|
||||
"message": "Rechercher une mise à jour",
|
||||
"description": "Label for the button to check a single style for an update"
|
||||
},
|
||||
"checkingForUpdate": {
|
||||
|
@ -292,6 +292,10 @@
|
|||
"message": "Glisser votre fichier de sauvegarde n’importe où sur cette page pour l’importer.",
|
||||
"description": "Drag'n'drop message"
|
||||
},
|
||||
"dragDropUsercssTabstrip": {
|
||||
"message": "Pour installer le fichier, glisser le fichier sur la barre des onglets (la zone où les titres des onglets sont affichés).",
|
||||
"description": "Message popup shown when erroneously dropping a usercss file into the manager page"
|
||||
},
|
||||
"editDeleteText": {
|
||||
"message": "Supprimer",
|
||||
"description": "Label for the context menu item in the editor to delete selected text"
|
||||
|
@ -617,6 +621,14 @@
|
|||
"message": "Une erreur est survenue durant la surveillance du fichier",
|
||||
"description": "The label of live-reload error"
|
||||
},
|
||||
"liveReloadInstallHint": {
|
||||
"message": "Gardez cet onglet ouvert pour mettre à jour le style automatiquement basé sur les modifications extérieures.",
|
||||
"description": "The label of live-reload feature"
|
||||
},
|
||||
"liveReloadInstallHintFF": {
|
||||
"message": "Gardez cet onglet ouvert ainsi que l´onglet original pour mettre à jour le style automatiquement basé sur les modifications extérieures.",
|
||||
"description": "The extra hint of live-reload feature shown only for file:// URLs in Firefox"
|
||||
},
|
||||
"liveReloadLabel": {
|
||||
"message": "Rechargement immédiat",
|
||||
"description": "The label of live-reload feature"
|
||||
|
@ -674,15 +686,15 @@
|
|||
"description": "Tooltip for the checkbox to show only locally created styles i.e. non-updatable"
|
||||
},
|
||||
"manageOnlyNonUsercss": {
|
||||
"message": "Uniquement les styles non Usercss",
|
||||
"message": "Styles non Usercss uniquement",
|
||||
"description": "Checkbox to show only non-Usercss (standard) styles"
|
||||
},
|
||||
"manageOnlyUpdates": {
|
||||
"message": "Uniquement avec mises à jour ou problèmes",
|
||||
"message": "Avec mises à jour ou problèmes uniquement",
|
||||
"description": "Checkbox to show only styles that have updates after check-all-styles-for-updates was performed"
|
||||
},
|
||||
"manageOnlyUsercss": {
|
||||
"message": "Uniquement les styles Usercss",
|
||||
"message": "Styles Usercss uniquement",
|
||||
"description": "Checkbox to show only Usercss styles"
|
||||
},
|
||||
"menuShowBadge": {
|
||||
|
@ -1464,7 +1476,7 @@
|
|||
"description": "Note in the toolbar popup for some file types that cannot be accessed"
|
||||
},
|
||||
"updateAllCheckSucceededNoUpdate": {
|
||||
"message": "All styles are up to date.",
|
||||
"message": "Aucune mise à jour trouvée.",
|
||||
"description": "Text that displays when an update all check completed and no updates are available"
|
||||
},
|
||||
"updateAllCheckSucceededSomeEdited": {
|
||||
|
|
|
@ -1162,7 +1162,7 @@
|
|||
"description": "Label for the checkbox controlling 'edit' action behavior in the popup."
|
||||
},
|
||||
"popupStylesFirst": {
|
||||
"message": "スタイルをコマンドボタンより上に表示",
|
||||
"message": "スタイル一覧をコマンドボタンより上に表示",
|
||||
"description": "Label for the checkbox controlling section order in the popup."
|
||||
},
|
||||
"prefShowBadge": {
|
||||
|
@ -1305,6 +1305,10 @@
|
|||
"message": "書式整形",
|
||||
"description": "Label for the CSS-beautifier button on the edit style page"
|
||||
},
|
||||
"styleBeautifyHint": {
|
||||
"message": "ヒント: 書式整形ボタンを右クリックするか、下で設定したキーボードショートカットを使用すると、このパネルを表示せずに書式設定が行えます",
|
||||
"description": "Hint shown inside the CSS-beautifier panel"
|
||||
},
|
||||
"styleBeautifyIndentConditional": {
|
||||
"message": "@media, @supports をインデント",
|
||||
"description": "CSS-beautifier option"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1285,6 +1285,10 @@
|
|||
"message": "Mooier maken",
|
||||
"description": "Label for the CSS-beautifier button on the edit style page"
|
||||
},
|
||||
"styleBeautifyHint": {
|
||||
"message": "Hint: klik met de rechtermuisknop op de knop ‘Mooier maken’ of gebruik de hieronder gedefinieerde sneltoets om iets mooier te maken zonder dit paneel te tonen",
|
||||
"description": "Hint shown inside the CSS-beautifier panel"
|
||||
},
|
||||
"styleBeautifyIndentConditional": {
|
||||
"message": "@media, @supports inspringen",
|
||||
"description": "CSS-beautifier option"
|
||||
|
|
|
@ -1309,6 +1309,10 @@
|
|||
"message": "Upiększ",
|
||||
"description": "Label for the CSS-beautifier button on the edit style page"
|
||||
},
|
||||
"styleBeautifyHint": {
|
||||
"message": "Wskazówka: kliknij prawym przyciskiem myszy przycisk “Upiększ” lub użyj zdefiniowanego poniżej skrótu klawiaturowego, aby upiększyć bez pokazywania tego panelu",
|
||||
"description": "Hint shown inside the CSS-beautifier panel"
|
||||
},
|
||||
"styleBeautifyIndentConditional": {
|
||||
"message": "Wcięcie @media, @supports",
|
||||
"description": "CSS-beautifier option"
|
||||
|
|
|
@ -244,6 +244,14 @@
|
|||
"message": "Да",
|
||||
"description": "'Yes' button in a confirm dialog"
|
||||
},
|
||||
"copied": {
|
||||
"message": "Скопировано в буфер обмена",
|
||||
"description": "Message shown when content has been copied to the clipboard"
|
||||
},
|
||||
"copy": {
|
||||
"message": "Скопировать в буфер обмена",
|
||||
"description": "Tooltip for elements which can be copied"
|
||||
},
|
||||
"dateInstalled": {
|
||||
"message": "Дата установки",
|
||||
"description": "Option text for the user to sort the style by install date"
|
||||
|
@ -284,6 +292,10 @@
|
|||
"message": "Перетащите файл с резервной копией стилей в любое место этой страницы, чтобы импортировать его.",
|
||||
"description": "Drag'n'drop message"
|
||||
},
|
||||
"dragDropUsercssTabstrip": {
|
||||
"message": "Чтобы установить файл, поместите его на вкладку (область, где отображаются заголовки вкладок).",
|
||||
"description": "Message popup shown when erroneously dropping a usercss file into the manager page"
|
||||
},
|
||||
"editDeleteText": {
|
||||
"message": "Удалить",
|
||||
"description": "Label for the context menu item in the editor to delete selected text"
|
||||
|
@ -441,6 +453,10 @@
|
|||
"message": "Нажмите клавишу",
|
||||
"description": "Placeholder text of inputbox in keymap help popup on the edit style page. Must be very short"
|
||||
},
|
||||
"hostDisabled": {
|
||||
"message": "Этот хост был отключен из-за ошибки в текущей версии используемого браузера",
|
||||
"description": "Tooltip for cloud host disabled"
|
||||
},
|
||||
"importAppendLabel": {
|
||||
"message": "Добавить к стилю",
|
||||
"description": "Label for the button to import a style and append to the existing sections"
|
||||
|
@ -613,6 +629,14 @@
|
|||
"message": "Ошибка слежения за файлом",
|
||||
"description": "The label of live-reload error"
|
||||
},
|
||||
"liveReloadInstallHint": {
|
||||
"message": "Держите эту вкладку открытой, чтобы автоматически обновлять стиль при внешних изменениях.",
|
||||
"description": "The label of live-reload feature"
|
||||
},
|
||||
"liveReloadInstallHintFF": {
|
||||
"message": "Оставьте эту вкладку и исходную вкладку открытой, чтобы автоматически обновлять стиль при внешних изменениях.",
|
||||
"description": "The extra hint of live-reload feature shown only for file:// URLs in Firefox"
|
||||
},
|
||||
"liveReloadLabel": {
|
||||
"message": "Автозагрузка изменений",
|
||||
"description": "The label of live-reload feature"
|
||||
|
@ -909,6 +933,10 @@
|
|||
"message": "Менеджер",
|
||||
"description": "Link to open the manage page."
|
||||
},
|
||||
"openOptions": {
|
||||
"message": "Опции",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"openStylesManager": {
|
||||
"message": "Менеджер стилей",
|
||||
"description": "Label for the style maanger opener in the browser action context menu."
|
||||
|
@ -969,6 +997,10 @@
|
|||
"message": "Обновления",
|
||||
"description": ""
|
||||
},
|
||||
"optionsCustomizeSync": {
|
||||
"message": "Синхронизация с облаком",
|
||||
"description": ""
|
||||
},
|
||||
"optionsHeading": {
|
||||
"message": "Настройки",
|
||||
"description": "Heading for options section on manage page."
|
||||
|
@ -1013,6 +1045,70 @@
|
|||
"message": "Интервал обновления стилей, в часах (укажите 0 для выключения)",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncNone": {
|
||||
"message": "Ничего",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncConnect": {
|
||||
"message": "Подключить",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncDisconnect": {
|
||||
"message": "Отсоединить",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncSyncNow": {
|
||||
"message": "Синхронизировать",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncLogin": {
|
||||
"message": "Логин",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusPull": {
|
||||
"message": "Загружено стилей $loaded$ из $total$",
|
||||
"description": "",
|
||||
"placeholders": {
|
||||
"loaded": {
|
||||
"content": "$1"
|
||||
},
|
||||
"total": {
|
||||
"content": "$2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsSyncStatusPush": {
|
||||
"message": "Загружено стилей $loaded$ из $total$",
|
||||
"description": "",
|
||||
"placeholders": {
|
||||
"loaded": {
|
||||
"content": "$1"
|
||||
},
|
||||
"total": {
|
||||
"content": "$2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsSyncStatusSyncing": {
|
||||
"message": "Синхронизация",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusConnecting": {
|
||||
"message": "Подключение…",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusConnected": {
|
||||
"message": "Подключено",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusDisconnecting": {
|
||||
"message": "Отсоединение…",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusDisconnected": {
|
||||
"message": "Отсоединено",
|
||||
"description": ""
|
||||
},
|
||||
"paginationCurrent": {
|
||||
"message": "Текущая страница",
|
||||
"description": "Tooltip for the current page index in search results"
|
||||
|
@ -1089,6 +1185,10 @@
|
|||
"message": "Временно применяет стиль пока вы его редактируете.\nСохраните стиль, чтобы сделать изменения постоянными.",
|
||||
"description": "Tooltip for the checkbox in style editor to enable live preview while editing."
|
||||
},
|
||||
"reload": {
|
||||
"message": "Перезагрузить расширение Stylus",
|
||||
"description": "Context menu reload"
|
||||
},
|
||||
"replace": {
|
||||
"message": "Заменить",
|
||||
"description": "Label before the replace input field in the editor shown on Ctrl-H"
|
||||
|
@ -1496,6 +1596,10 @@
|
|||
"message": "Экспорт Dropbox",
|
||||
"description": ""
|
||||
},
|
||||
"syncDropboxDeprecated": {
|
||||
"message": "Импорт/экспорт Dropbox заменен более продвинутой синхронизацией стилей на странице параметров.",
|
||||
"description": ""
|
||||
},
|
||||
"retrieveDropboxSync": {
|
||||
"message": "Импорт Dropbox",
|
||||
"description": ""
|
||||
|
|
|
@ -40,6 +40,10 @@
|
|||
"message": "Şuraya uygulanır",
|
||||
"description": "Label for 'applies to' fields on the edit/add screen"
|
||||
},
|
||||
"appliesLineWidgetWarning": {
|
||||
"message": "Küçültülmüş CSS ile çalışmaz",
|
||||
"description": "A warning that applies-to information won't show properly with minified CSS"
|
||||
},
|
||||
"appliesRegexpOption": {
|
||||
"message": "regexp ile eşleşen URL'ler",
|
||||
"description": "Option to make the style apply to the entered string as a regular expression"
|
||||
|
@ -68,6 +72,14 @@
|
|||
"message": "Yazar",
|
||||
"description": "Label for the style author"
|
||||
},
|
||||
"backupButtons": {
|
||||
"message": "Yedek",
|
||||
"description": "Heading for backup"
|
||||
},
|
||||
"backupMessage": {
|
||||
"message": "Bir dosya seçin veya bu sayfaya sürükleyip bırakın.",
|
||||
"description": "Message for backup"
|
||||
},
|
||||
"bckpInstStyles": {
|
||||
"message": "Dışa aktar",
|
||||
"description": ""
|
||||
|
@ -76,6 +88,10 @@
|
|||
"message": "Tüm stiller için güncellemeleri denetle",
|
||||
"description": "Label for the button to check all styles for updates"
|
||||
},
|
||||
"checkAllUpdatesForce": {
|
||||
"message": "Tekrar kontrol et, herhangi bir stil düzenlemedim!",
|
||||
"description": "Label for the button to apply all detected updates"
|
||||
},
|
||||
"checkForUpdate": {
|
||||
"message": "Güncellemeleri denetle",
|
||||
"description": "Label for the button to check a single style for an update"
|
||||
|
@ -92,6 +108,10 @@
|
|||
"message": "Parantezleri ve tırnak işaretlerini otomatik olarak kapat",
|
||||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"cm_autoCloseBracketsTooltip": {
|
||||
"message": "()[]{}''\"\" Açılışlarından birini yazarken otomatik olarak bir kapanış çifti ekleyin",
|
||||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"cm_autocompleteOnTyping": {
|
||||
"message": "Yazarken tamamla",
|
||||
"description": "Label for the checkbox in the style editor."
|
||||
|
@ -104,6 +124,14 @@
|
|||
"message": "Akıllı girintili tab kullan",
|
||||
"description": "Label for the checkbox controlling tabs with smart indentation option for the style editor."
|
||||
},
|
||||
"cm_keyMap": {
|
||||
"message": "Tuşeşlem",
|
||||
"description": "Label for the drop-down list controlling the keymap for the style editor."
|
||||
},
|
||||
"cm_lineWrapping": {
|
||||
"message": "Kelime kaydırma",
|
||||
"description": "Label for the checkbox controlling word wrap option for the style editor."
|
||||
},
|
||||
"cm_matchHighlight": {
|
||||
"message": "Vurgulama",
|
||||
"description": "Label for the drop-down list controlling the automatic highlighting of current word/selection occurrences in the style editor."
|
||||
|
@ -112,6 +140,26 @@
|
|||
"message": "Yalnızca seçim",
|
||||
"description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of currently selected text"
|
||||
},
|
||||
"cm_matchHighlightToken": {
|
||||
"message": "İmleç altındaki token",
|
||||
"description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of the word/token under cursor even if nothing is selected"
|
||||
},
|
||||
"cm_resizeGripHint": {
|
||||
"message": "Yüksekliği en üst düzeye çıkarmak/geri yüklemek için çift tıklayın",
|
||||
"description": "Tooltip for the resize grip in style editor"
|
||||
},
|
||||
"cm_selectByTokens": {
|
||||
"message": "Çift tıklamak tokenleri seçer",
|
||||
"description": "Label for the checkbox in the editor."
|
||||
},
|
||||
"cm_selectByTokensTooltip": {
|
||||
"message": "Token örnekleri: .foo-bar-2 #aabbcc 0.32 !important\nDevre dışı bırakıldığında: noktalama işareti ile ayrılmış kelimeler seçilir.",
|
||||
"description": ""
|
||||
},
|
||||
"cm_smartIndent": {
|
||||
"message": "Akıllı girinti kullanma",
|
||||
"description": "Label for the checkbox controlling smart indentation option for the style editor."
|
||||
},
|
||||
"cm_tabSize": {
|
||||
"message": "Tab büyüklüğü",
|
||||
"description": "Label for the text box controlling tab size option for the style editor."
|
||||
|
@ -120,10 +168,30 @@
|
|||
"message": "Tema",
|
||||
"description": "Label for the style editor's CSS theme."
|
||||
},
|
||||
"colorpickerSwitchFormatTooltip": {
|
||||
"message": "Format değişimleri: HEX -> RGB -> HSL.\nYönü ters çevirmek için Shift tuşunu basılı tutup tıklatın.\nAyrıca PgUp (PageUp), PgDn (PageDown) tuşları ile.",
|
||||
"description": "Tooltip for the switch button in the color picker popup in the style editor."
|
||||
},
|
||||
"colorpickerTooltip": {
|
||||
"message": "Renk seçiciyi aç",
|
||||
"description": "Tooltip for the colored squares shown before CSS colors in the style editor."
|
||||
},
|
||||
"configOnChange": {
|
||||
"message": "değişiklikte",
|
||||
"description": "VERY SHORT label for the checkbox in style config dialog after the save button - when enabled the changes in the dialog are saved and applied automatically without the need to press the Save button"
|
||||
},
|
||||
"configOnChangeTooltip": {
|
||||
"message": "Otomatik kaydetme ve değişiklikleri otomatik olarak uygulama",
|
||||
"description": ""
|
||||
},
|
||||
"configureStyle": {
|
||||
"message": "Yapılandır",
|
||||
"description": "Label for the button to configure usercss userstyle"
|
||||
},
|
||||
"configureStyleOnHomepage": {
|
||||
"message": "Ana sayfada yapılandır",
|
||||
"description": "Label for the button to configure userstyles.org userstyle"
|
||||
},
|
||||
"confirmCancel": {
|
||||
"message": "İptal",
|
||||
"description": ""
|
||||
|
@ -180,6 +248,10 @@
|
|||
"message": "Güncelleme tarihi",
|
||||
"description": "Option text for the user to sort the style by last update date"
|
||||
},
|
||||
"dbError": {
|
||||
"message": "Stylus veritabanı kullanılırken bir hata oluştu. Olası çözümler içeren bir web sayfasını ziyaret etmek ister misiniz?",
|
||||
"description": "Prompt when a DB error is encountered"
|
||||
},
|
||||
"defaultTheme": {
|
||||
"message": "öntanımlı",
|
||||
"description": "Default CodeMirror CSS theme option on the edit style page"
|
||||
|
@ -204,6 +276,14 @@
|
|||
"message": "Devre dışı bırak",
|
||||
"description": "Label for the button to disable a style"
|
||||
},
|
||||
"dragDropMessage": {
|
||||
"message": "İçe aktarmak için yedek dosyanızı bu sayfada herhangi bir yere bırakın.",
|
||||
"description": "Drag'n'drop message"
|
||||
},
|
||||
"dragDropUsercssTabstrip": {
|
||||
"message": "Dosyayı yüklemek için sekme şeridine (sekme başlıklarının gösterildiği alan) bırakın.",
|
||||
"description": "Message popup shown when erroneously dropping a usercss file into the manager page"
|
||||
},
|
||||
"editDeleteText": {
|
||||
"message": "Sil",
|
||||
"description": "Label for the context menu item in the editor to delete selected text"
|
||||
|
@ -237,6 +317,14 @@
|
|||
"message": "Etkinleştir",
|
||||
"description": "Label for the button to enable a style"
|
||||
},
|
||||
"excludeStyleByDomainLabel": {
|
||||
"message": "Mevcut alan adını hariç tut",
|
||||
"description": ""
|
||||
},
|
||||
"excludeStyleByUrlLabel": {
|
||||
"message": "Mevcut URL'yi hariç tut",
|
||||
"description": ""
|
||||
},
|
||||
"exportLabel": {
|
||||
"message": "Dışa aktar",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
|
@ -249,10 +337,34 @@
|
|||
"message": "Anasayfa",
|
||||
"description": "Label for the external link to style's homepage"
|
||||
},
|
||||
"externalLink": {
|
||||
"message": "Harici bağlantı",
|
||||
"description": "Label for external links"
|
||||
},
|
||||
"externalSupport": {
|
||||
"message": "Destek",
|
||||
"description": "Label for the external link to style's support site"
|
||||
},
|
||||
"externalUsercssDocument": {
|
||||
"message": "Usercss belgeleri",
|
||||
"description": "Label for the external link to usercss documentation"
|
||||
},
|
||||
"filteredStyles": {
|
||||
"message": "Toplam $numTotal$ gösterilen $numShown$",
|
||||
"description": "TL note - make this message short",
|
||||
"placeholders": {
|
||||
"numTotal": {
|
||||
"content": "$2"
|
||||
},
|
||||
"numShown": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"filteredStylesAllHidden": {
|
||||
"message": "Şu anda uygulanan filtreler hiçbir stille eşleşmiyor",
|
||||
"description": "Text shown when no styles match currently applied filter in the style manager"
|
||||
},
|
||||
"findStyles": {
|
||||
"message": "Stil bul",
|
||||
"description": "Text for a link that gets a list of styles for the current site"
|
||||
|
@ -261,10 +373,22 @@
|
|||
"message": "Bu site için başka stiller bul",
|
||||
"description": "Text for a link that gets a list of styles for the current site"
|
||||
},
|
||||
"findStylesInline": {
|
||||
"message": "Hizada",
|
||||
"description": "Text for a checkbox that opens search results 'inline' (within the Stylus popup window)"
|
||||
},
|
||||
"findStylesInlineTooltip": {
|
||||
"message": "Arama sonuçlarını bu pencerede görüntüleyin.",
|
||||
"description": "Text for a checkbox that displays search results within the Stylus popup."
|
||||
},
|
||||
"genericAdd": {
|
||||
"message": "Ekle",
|
||||
"description": "Used in various places for an action that adds something"
|
||||
},
|
||||
"genericClone": {
|
||||
"message": "Klon",
|
||||
"description": "Used in various places for an action that clones something"
|
||||
},
|
||||
"genericDisabledLabel": {
|
||||
"message": "Devre dışı",
|
||||
"description": "Used in various lists/options to indicate that something is disabled"
|
||||
|
@ -289,6 +413,10 @@
|
|||
"message": "Önceki",
|
||||
"description": "Used in various places to select/perform the previous step/action"
|
||||
},
|
||||
"genericResetLabel": {
|
||||
"message": "Yenile",
|
||||
"description": "Used in various parts of UI to indicate that something may be reset to its original state"
|
||||
},
|
||||
"genericSavedMessage": {
|
||||
"message": "Kaydedildi",
|
||||
"description": "Used in various parts of the UI to indicate that something was saved"
|
||||
|
@ -305,10 +433,26 @@
|
|||
"message": "Yardım",
|
||||
"description": "Alternate text for help buttons"
|
||||
},
|
||||
"helpKeyMapCommand": {
|
||||
"message": "Bir komut adı yazın",
|
||||
"description": "Placeholder text of inputbox in keymap help popup on the edit style page. Must be very short"
|
||||
},
|
||||
"helpKeyMapHotkey": {
|
||||
"message": "Bir kısayol tuşuna basın",
|
||||
"description": "Placeholder text of inputbox in keymap help popup on the edit style page. Must be very short"
|
||||
},
|
||||
"hostDisabled": {
|
||||
"message": "Bu ana bilgisayar, kullanılan tarayıcının mevcut sürümündeki bir hata nedeniyle devre dışı bırakıldı",
|
||||
"description": "Tooltip for cloud host disabled"
|
||||
},
|
||||
"importAppendLabel": {
|
||||
"message": "Stile ekle",
|
||||
"description": "Label for the button to import a style and append to the existing sections"
|
||||
},
|
||||
"importAppendTooltip": {
|
||||
"message": "İçe aktarılan stili geçerli stile ekleme",
|
||||
"description": "Tooltip for the button to import a style and append to the existing sections"
|
||||
},
|
||||
"importLabel": {
|
||||
"message": "İçe aktar",
|
||||
"description": "Label for the button to import a style ('edit' page) or all styles ('manage' page)"
|
||||
|
@ -317,10 +461,18 @@
|
|||
"message": "Stilin üzerine yaz",
|
||||
"description": "Label for the button to import and overwrite current style"
|
||||
},
|
||||
"importReplaceTooltip": {
|
||||
"message": "Geçerli stilin içeriğini atın ve içe aktarılan stil ile üzerine yazın",
|
||||
"description": "Label for the button to import and overwrite current style"
|
||||
},
|
||||
"importReportLegendAdded": {
|
||||
"message": "eklendi",
|
||||
"description": "Text after the number of styles added in the report shown after importing styles"
|
||||
},
|
||||
"importReportLegendUpdatedBoth": {
|
||||
"message": "hem meta bilgi hem de kod güncellendi",
|
||||
"description": "Text after the number of styles updated entirely in the report shown after importing styles"
|
||||
},
|
||||
"importReportLegendUpdatedCode": {
|
||||
"message": "güncellenmiş kod",
|
||||
"description": "Text after the number of styles with updated code (meta info is unchanged) in the report shown after importing styles"
|
||||
|
@ -640,6 +792,10 @@
|
|||
"message": "Güncelleme kontrolü geçmişi",
|
||||
"description": ""
|
||||
},
|
||||
"updateCheckSkippedMaybeLocallyEdited": {
|
||||
"message": "Bu stil yerel olarak düzenlenmiş olabilir.",
|
||||
"description": "Text that displays when an update check skipped updating the style to avoid losing possible local modifications"
|
||||
},
|
||||
"updateCheckSucceededNoUpdate": {
|
||||
"message": "Stil güncel.",
|
||||
"description": "Text that displays when an update check completed and no update is available"
|
||||
|
@ -652,6 +808,38 @@
|
|||
"message": "Kurulan güncellemeler:",
|
||||
"description": "Text that displays when an update is installed on options page. Followed by the number of currently installed updates."
|
||||
},
|
||||
"usercssAvoidOverwriting": {
|
||||
"message": "Mevcut bir stilin üzerine yazmaktan kaçınmak için lütfen @name veya @ ad alanının değerini değiştirin.",
|
||||
"description": "Shown in a message box when attempting to save a new Usercss style that would overwrite an existing one."
|
||||
},
|
||||
"usercssConfigIncomplete": {
|
||||
"message": "Stil, yapılandırma iletişim kutusu gösterildikten sonra güncellendi veya silindi. Bu değişkenler, stilin meta verilerini bozmamak için kaydedilmedi:",
|
||||
"description": ""
|
||||
},
|
||||
"usercssEditorNamePlaceholder": {
|
||||
"message": "Kodda @name belirtin",
|
||||
"description": "Placeholder text for the empty name input field when creating a new Usercss style"
|
||||
},
|
||||
"usercssReplaceTemplateConfirmation": {
|
||||
"message": "Yeni Usercss stilleri için varsayılan şablonu geçerli kodla değiştir?",
|
||||
"description": ""
|
||||
},
|
||||
"usercssReplaceTemplateName": {
|
||||
"message": "Boş @name, varsayılan şablonun yerini alır",
|
||||
"description": "The text shown after @name when creating a new Usercss style"
|
||||
},
|
||||
"usercssReplaceTemplateSectionBody": {
|
||||
"message": "Kodu buraya ekle...",
|
||||
"description": "The code placeholder comment in a new style created by clicking 'Write style' in the popup"
|
||||
},
|
||||
"versionInvalidOlder": {
|
||||
"message": "Sürüm, kurulu stillerden daha eski.",
|
||||
"description": "Displayed when the version of style is older than the installed one"
|
||||
},
|
||||
"writeStyleFor": {
|
||||
"message": "Şunun için stil yaz:",
|
||||
"description": "Label for toolbar pop-up that precedes the links to write a new style"
|
||||
},
|
||||
"writeStyleForURL": {
|
||||
"message": "bu URL",
|
||||
"description": "Text for link in toolbar pop-up to write a new style for the current URL"
|
||||
|
@ -660,14 +848,34 @@
|
|||
"message": "Dropbox'tan aktar",
|
||||
"description": ""
|
||||
},
|
||||
"syncDropboxDeprecated": {
|
||||
"message": "Dropbox içe/dışa aktarma, seçenekler sayfasında daha gelişmiş bir stil senkronizasyonu ile değiştirilir.",
|
||||
"description": ""
|
||||
},
|
||||
"retrieveDropboxSync": {
|
||||
"message": "Dropbox'a aktar",
|
||||
"description": ""
|
||||
},
|
||||
"overwriteFileExport": {
|
||||
"message": "Mevcut bir dosyanın üzerine yazmak istiyor musunuz?",
|
||||
"description": ""
|
||||
},
|
||||
"exportSavedSuccess": {
|
||||
"message": "Dosya başarıyla kaydedildi",
|
||||
"description": ""
|
||||
},
|
||||
"noFileToImport": {
|
||||
"message": "Stillerinizi içe aktarmak için önce dışa aktarmanız gerekir.",
|
||||
"description": ""
|
||||
},
|
||||
"connectingDropbox": {
|
||||
"message": "Dropbox'a bağlanıyor...",
|
||||
"description": ""
|
||||
},
|
||||
"connectingDropboxNotAllowed": {
|
||||
"message": "Dropbox'a bağlanmak yalnızca doğrudan web mağazasından yüklenen uygulamalarda kullanılabilir",
|
||||
"description": ""
|
||||
},
|
||||
"gettingStyles": {
|
||||
"message": "Tüm stiller alınıyor...",
|
||||
"description": ""
|
||||
|
@ -676,6 +884,10 @@
|
|||
"message": "Stiller sıkıştırılıyor...",
|
||||
"description": ""
|
||||
},
|
||||
"unzipStyles": {
|
||||
"message": "Stiller açılıyor...",
|
||||
"description": ""
|
||||
},
|
||||
"readingStyles": {
|
||||
"message": "Stiller okunuyor...",
|
||||
"description": ""
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"cm_autocompleteOnTyping": {
|
||||
"message": "输入时自动完成",
|
||||
"message": "输入时自动补全",
|
||||
"description": "Label for the checkbox in the style editor."
|
||||
},
|
||||
"cm_colorpicker": {
|
||||
|
@ -133,7 +133,7 @@
|
|||
"description": "Label for the checkbox controlling colorpicker option for the style editor."
|
||||
},
|
||||
"cm_indentWithTabs": {
|
||||
"message": "使用 Tab 智能缩进",
|
||||
"message": "使用Tab智能缩进",
|
||||
"description": "Label for the checkbox controlling tabs with smart indentation option for the style editor."
|
||||
},
|
||||
"cm_keyMap": {
|
||||
|
@ -153,7 +153,7 @@
|
|||
"description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of currently selected text"
|
||||
},
|
||||
"cm_matchHighlightToken": {
|
||||
"message": "光标所在 token 字段",
|
||||
"message": "光标所在token字段",
|
||||
"description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of the word/token under cursor even if nothing is selected"
|
||||
},
|
||||
"cm_resizeGripHint": {
|
||||
|
@ -244,6 +244,14 @@
|
|||
"message": "是",
|
||||
"description": "'Yes' button in a confirm dialog"
|
||||
},
|
||||
"copied": {
|
||||
"message": "已复制到粘贴板",
|
||||
"description": "Message shown when content has been copied to the clipboard"
|
||||
},
|
||||
"copy": {
|
||||
"message": "复制到粘贴板",
|
||||
"description": "Tooltip for elements which can be copied"
|
||||
},
|
||||
"dateInstalled": {
|
||||
"message": "安装日期",
|
||||
"description": "Option text for the user to sort the style by install date"
|
||||
|
@ -284,6 +292,10 @@
|
|||
"message": "把 JSON 备份文件拖放到页面的任意位置,即可导入",
|
||||
"description": "Drag'n'drop message"
|
||||
},
|
||||
"dragDropUsercssTabstrip": {
|
||||
"message": "要安装文件,就将其放在选项卡条(显示选项卡标题的区域)上。",
|
||||
"description": "Message popup shown when erroneously dropping a usercss file into the manager page"
|
||||
},
|
||||
"editDeleteText": {
|
||||
"message": "删除",
|
||||
"description": "Label for the context menu item in the editor to delete selected text"
|
||||
|
@ -441,6 +453,10 @@
|
|||
"message": "按下热键",
|
||||
"description": "Placeholder text of inputbox in keymap help popup on the edit style page. Must be very short"
|
||||
},
|
||||
"hostDisabled": {
|
||||
"message": "由于当前使用的浏览器版本中存在的错误,此主机已被禁用",
|
||||
"description": "Tooltip for cloud host disabled"
|
||||
},
|
||||
"importAppendLabel": {
|
||||
"message": "追加到样式",
|
||||
"description": "Label for the button to import a style and append to the existing sections"
|
||||
|
@ -609,6 +625,14 @@
|
|||
"message": "查看文件时发生错误",
|
||||
"description": "The label of live-reload error"
|
||||
},
|
||||
"liveReloadInstallHint": {
|
||||
"message": "保持此选项卡为打开状态,将在外部更改后自动更新样式。",
|
||||
"description": "The label of live-reload feature"
|
||||
},
|
||||
"liveReloadInstallHintFF": {
|
||||
"message": "保持此选项卡和原始选项卡处于打开状态,将在外部更改时自动重新更新样式。",
|
||||
"description": "The extra hint of live-reload feature shown only for file:// URLs in Firefox"
|
||||
},
|
||||
"liveReloadLabel": {
|
||||
"message": "动态刷新",
|
||||
"description": "The label of live-reload feature"
|
||||
|
@ -642,7 +666,7 @@
|
|||
"description": "VERY SHORT label for the checkbox next to the 'Write new style' button in the style manager"
|
||||
},
|
||||
"manageNewUI": {
|
||||
"message": "新的样式管理界面",
|
||||
"message": "新版管理器",
|
||||
"description": "Label for the checkbox that toggles the new UI on manage page"
|
||||
},
|
||||
"manageOnlyDisabled": {
|
||||
|
@ -905,6 +929,10 @@
|
|||
"message": "管理样式",
|
||||
"description": "Link to open the manage page."
|
||||
},
|
||||
"openOptions": {
|
||||
"message": "选项",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"openStylesManager": {
|
||||
"message": "打开样式管理器",
|
||||
"description": "Label for the style maanger opener in the browser action context menu."
|
||||
|
@ -965,6 +993,10 @@
|
|||
"message": "检测更新",
|
||||
"description": ""
|
||||
},
|
||||
"optionsCustomizeSync": {
|
||||
"message": "同步到云端",
|
||||
"description": ""
|
||||
},
|
||||
"optionsHeading": {
|
||||
"message": "选项",
|
||||
"description": "Heading for options section on manage page."
|
||||
|
@ -1009,6 +1041,70 @@
|
|||
"message": "每隔 N 小时,检查所有样式更新(0 为关闭检查)",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncNone": {
|
||||
"message": "无",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncConnect": {
|
||||
"message": "连接",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncDisconnect": {
|
||||
"message": "断开连接",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncSyncNow": {
|
||||
"message": "现在同步",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncLogin": {
|
||||
"message": "登录",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusPull": {
|
||||
"message": "正在获取样式 $loaded$ 中的 $total$",
|
||||
"description": "",
|
||||
"placeholders": {
|
||||
"loaded": {
|
||||
"content": "$1"
|
||||
},
|
||||
"total": {
|
||||
"content": "$2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsSyncStatusPush": {
|
||||
"message": "正在上传样式 $loaded$ 中的 $total$",
|
||||
"description": "",
|
||||
"placeholders": {
|
||||
"loaded": {
|
||||
"content": "$1"
|
||||
},
|
||||
"total": {
|
||||
"content": "$2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsSyncStatusSyncing": {
|
||||
"message": "同步中...",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusConnecting": {
|
||||
"message": "连接中...",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusConnected": {
|
||||
"message": "已连接",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusDisconnecting": {
|
||||
"message": "正在断开连接...",
|
||||
"description": ""
|
||||
},
|
||||
"optionsSyncStatusDisconnected": {
|
||||
"message": "已断开连接",
|
||||
"description": ""
|
||||
},
|
||||
"paginationCurrent": {
|
||||
"message": "当前页数",
|
||||
"description": "Tooltip for the current page index in search results"
|
||||
|
@ -1085,6 +1181,10 @@
|
|||
"message": "无需保存即可临时应用样式预览效果。保存以使更改永久生效。",
|
||||
"description": "Tooltip for the checkbox in style editor to enable live preview while editing."
|
||||
},
|
||||
"reload": {
|
||||
"message": "重新加载 Stylus 扩展程序",
|
||||
"description": "Context menu reload"
|
||||
},
|
||||
"replace": {
|
||||
"message": "替换",
|
||||
"description": "Label before the replace input field in the editor shown on Ctrl-H"
|
||||
|
@ -1209,6 +1309,10 @@
|
|||
"message": "格式化",
|
||||
"description": "Label for the CSS-beautifier button on the edit style page"
|
||||
},
|
||||
"styleBeautifyHint": {
|
||||
"message": "提示: 你可以不显示此面板, 而是用右键“美化”按钮 或用下面定义的快捷键来美化.",
|
||||
"description": "Hint shown inside the CSS-beautifier panel"
|
||||
},
|
||||
"styleBeautifyIndentConditional": {
|
||||
"message": "缩进 @media、@supports",
|
||||
"description": "CSS-beautifier option"
|
||||
|
@ -1218,7 +1322,7 @@
|
|||
"description": "CSS-beautifier option"
|
||||
},
|
||||
"styleCancelEditLabel": {
|
||||
"message": "返回管理页面",
|
||||
"message": "返回管理器",
|
||||
"description": "Label for cancel button for style editing"
|
||||
},
|
||||
"styleChangesNotSaved": {
|
||||
|
@ -1492,6 +1596,10 @@
|
|||
"message": "导出至 Dropbox",
|
||||
"description": ""
|
||||
},
|
||||
"syncDropboxDeprecated": {
|
||||
"message": "在选项页面中, Dropbox 导入/导出 已经替换为更高级的样式同步方式。",
|
||||
"description": ""
|
||||
},
|
||||
"retrieveDropboxSync": {
|
||||
"message": "从 Dropbox 导入",
|
||||
"description": ""
|
||||
|
|
|
@ -1309,6 +1309,10 @@
|
|||
"message": "美化",
|
||||
"description": "Label for the CSS-beautifier button on the edit style page"
|
||||
},
|
||||
"styleBeautifyHint": {
|
||||
"message": "提示:右鍵點選「美化」按鈕或使用下面定義的鍵盤快捷鍵來美化而不顯示此面板",
|
||||
"description": "Hint shown inside the CSS-beautifier panel"
|
||||
},
|
||||
"styleBeautifyIndentConditional": {
|
||||
"message": "縮排 @media, @supports",
|
||||
"description": "CSS-beautifier option"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* global download prefs openURL FIREFOX CHROME
|
||||
URLS ignoreChromeError usercssHelper
|
||||
styleManager msg navigatorUtil workerUtil contentScripts sync
|
||||
findExistingTab createTab activateTab isTabReplaceable getActiveTab
|
||||
findExistingTab activateTab isTabReplaceable getActiveTab
|
||||
tabManager colorScheme */
|
||||
'use strict';
|
||||
|
||||
|
@ -10,6 +10,20 @@ var backgroundWorker = workerUtil.createWorker({
|
|||
url: '/background/background-worker.js'
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var browserCommands, contextMenus;
|
||||
|
||||
// *************************************************************************
|
||||
// browser commands
|
||||
browserCommands = {
|
||||
openManage,
|
||||
openOptions: () => openManage({options: true}),
|
||||
styleDisableAll(info) {
|
||||
prefs.set('disableAll', info ? info.checked : !prefs.get('disableAll'));
|
||||
},
|
||||
reload: () => chrome.runtime.reload(),
|
||||
};
|
||||
|
||||
window.API_METHODS = Object.assign(window.API_METHODS || {}, {
|
||||
deleteStyle: styleManager.deleteStyle,
|
||||
editSave: styleManager.editSave,
|
||||
|
@ -70,8 +84,8 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, {
|
|||
},
|
||||
|
||||
optionsCustomizeHotkeys() {
|
||||
return browser.runtime.openOptionsPage()
|
||||
.then(() => new Promise(resolve => setTimeout(resolve, 100)))
|
||||
return browserCommands.openOptions()
|
||||
.then(() => new Promise(resolve => setTimeout(resolve, 500)))
|
||||
.then(() => msg.broadcastExtension({method: 'optionsCustomizeHotkeys'}));
|
||||
},
|
||||
|
||||
|
@ -86,9 +100,6 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, {
|
|||
openManage
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var browserCommands, contextMenus;
|
||||
|
||||
// *************************************************************************
|
||||
// register all listeners
|
||||
msg.on(onRuntimeMessage);
|
||||
|
@ -148,17 +159,6 @@ chrome.runtime.onInstalled.addListener(({reason}) => {
|
|||
delete localStorage.codeMirrorThemes;
|
||||
});
|
||||
|
||||
// *************************************************************************
|
||||
// browser commands
|
||||
browserCommands = {
|
||||
openManage,
|
||||
openOptions: () => openManage({options: true}),
|
||||
styleDisableAll(info) {
|
||||
prefs.set('disableAll', info ? info.checked : !prefs.get('disableAll'));
|
||||
},
|
||||
reload: () => chrome.runtime.reload(),
|
||||
};
|
||||
|
||||
// *************************************************************************
|
||||
// context menus
|
||||
contextMenus = {
|
||||
|
@ -218,7 +218,7 @@ function createContextMenus(ids) {
|
|||
|
||||
if (chrome.contextMenus) {
|
||||
// circumvent the bug with disabling check marks in Chrome 62-64
|
||||
const toggleCheckmark = CHROME >= 3172 && CHROME <= 3288 ?
|
||||
const toggleCheckmark = CHROME >= 62 && CHROME <= 64 ?
|
||||
(id => chrome.contextMenus.remove(id, () => createContextMenus([id]) + ignoreChromeError())) :
|
||||
((id, checked) => chrome.contextMenus.update(id, {checked}, ignoreChromeError));
|
||||
|
||||
|
@ -337,7 +337,7 @@ function openManage({options = false, search} = {}) {
|
|||
if (isTabReplaceable(tab, url)) {
|
||||
return activateTab(tab, {url});
|
||||
}
|
||||
return createTab({url});
|
||||
return browser.tabs.create({url});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global msg queryTabs ignoreChromeError URLS */
|
||||
/* global msg ignoreChromeError URLS */
|
||||
/* exported contentScripts */
|
||||
'use strict';
|
||||
|
||||
|
@ -55,7 +55,7 @@ const contentScripts = (() => {
|
|||
}
|
||||
|
||||
function injectToAllTabs() {
|
||||
return queryTabs({}).then(tabs => {
|
||||
return browser.tabs.query({}).then(tabs => {
|
||||
for (const tab of tabs) {
|
||||
// skip unloaded/discarded/chrome tabs
|
||||
if (!tab.width || tab.discarded || !URLS.supported(tab.url)) continue;
|
||||
|
|
|
@ -1,46 +1,29 @@
|
|||
/* global promisify */
|
||||
/* global chromeLocal */
|
||||
/* exported createChromeStorageDB */
|
||||
'use strict';
|
||||
|
||||
function createChromeStorageDB() {
|
||||
const get = promisify(chrome.storage.local.get.bind(chrome.storage.local));
|
||||
const set = promisify(chrome.storage.local.set.bind(chrome.storage.local));
|
||||
const remove = promisify(chrome.storage.local.remove.bind(chrome.storage.local));
|
||||
|
||||
let INC;
|
||||
|
||||
const PREFIX = 'style-';
|
||||
const METHODS = {
|
||||
// FIXME: we don't use this method at all. Should we remove this?
|
||||
get: id => get(PREFIX + id)
|
||||
.then(result => result[PREFIX + id]),
|
||||
put: obj => Promise.resolve()
|
||||
.then(() => {
|
||||
if (!obj.id) {
|
||||
return prepareInc()
|
||||
.then(() => {
|
||||
// FIXME: should we clone the object?
|
||||
obj.id = INC++;
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => set({[PREFIX + obj.id]: obj}))
|
||||
.then(() => obj.id),
|
||||
get: id => chromeLocal.getValue(PREFIX + id),
|
||||
put: obj =>
|
||||
// FIXME: should we clone the object?
|
||||
Promise.resolve(!obj.id && prepareInc().then(() => Object.assign(obj, {id: INC++})))
|
||||
.then(() => chromeLocal.setValue(PREFIX + obj.id, obj))
|
||||
.then(() => obj.id),
|
||||
putMany: items => prepareInc()
|
||||
.then(() => {
|
||||
for (const item of items) {
|
||||
if (!item.id) {
|
||||
item.id = INC++;
|
||||
}
|
||||
}
|
||||
return set(items.reduce((obj, curr) => {
|
||||
obj[PREFIX + curr.id] = curr;
|
||||
return obj;
|
||||
}, {}));
|
||||
})
|
||||
.then(() =>
|
||||
chromeLocal.set(items.reduce((data, item) => {
|
||||
if (!item.id) item.id = INC++;
|
||||
data[PREFIX + item.id] = item;
|
||||
return data;
|
||||
}, {})))
|
||||
.then(() => items.map(i => i.id)),
|
||||
delete: id => remove(PREFIX + id),
|
||||
getAll: () => get(null)
|
||||
delete: id => chromeLocal.remove(PREFIX + id),
|
||||
getAll: () => chromeLocal.get()
|
||||
.then(result => {
|
||||
const output = [];
|
||||
for (const key in result) {
|
||||
|
@ -69,7 +52,7 @@ function createChromeStorageDB() {
|
|||
|
||||
function prepareInc() {
|
||||
if (INC) return Promise.resolve();
|
||||
return get(null).then(result => {
|
||||
return chromeLocal.get().then(result => {
|
||||
INC = 1;
|
||||
for (const key in result) {
|
||||
if (key.startsWith(PREFIX)) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
'use strict';
|
||||
|
||||
const iconManager = (() => {
|
||||
const ICON_SIZES = FIREFOX || CHROME >= 2883 && !VIVALDI ? [16, 32] : [19, 38];
|
||||
const ICON_SIZES = FIREFOX || CHROME >= 55 && !VIVALDI ? [16, 32] : [19, 38];
|
||||
const staleBadges = new Set();
|
||||
|
||||
prefs.subscribe([
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global promisify CHROME URLS */
|
||||
/* global CHROME URLS */
|
||||
/* exported navigatorUtil */
|
||||
'use strict';
|
||||
|
||||
|
@ -6,7 +6,6 @@ const navigatorUtil = (() => {
|
|||
const handler = {
|
||||
urlChange: null
|
||||
};
|
||||
const tabGet = promisify(chrome.tabs.get.bind(chrome.tabs));
|
||||
return extendNative({onUrlChange});
|
||||
|
||||
function onUrlChange(fn) {
|
||||
|
@ -48,7 +47,7 @@ const navigatorUtil = (() => {
|
|||
) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return tabGet(data.tabId)
|
||||
return browser.tabs.get(data.tabId)
|
||||
.then(tab => {
|
||||
if (tab.url === 'chrome://newtab/') {
|
||||
data.url = tab.url;
|
||||
|
|
|
@ -192,6 +192,7 @@ const sync = (() => {
|
|||
.catch(handle401Error)
|
||||
.then(() => syncNow()),
|
||||
err => {
|
||||
status.errorMessage = err ? err.message : null;
|
||||
// FIXME: should we move this logic to options.js?
|
||||
if (err && !fromPref) {
|
||||
console.error(err);
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
/* global chromeLocal promisify FIREFOX */
|
||||
/* global chromeLocal promisifyChrome FIREFOX */
|
||||
/* exported tokenManager */
|
||||
'use strict';
|
||||
|
||||
const tokenManager = (() => {
|
||||
const launchWebAuthFlow = promisify(chrome.identity.launchWebAuthFlow.bind(chrome.identity));
|
||||
promisifyChrome({
|
||||
identity: ['launchWebAuthFlow'],
|
||||
});
|
||||
const AUTH = {
|
||||
dropbox: {
|
||||
flow: 'token',
|
||||
|
@ -158,7 +160,7 @@ const tokenManager = (() => {
|
|||
Object.assign(query, provider.authQuery);
|
||||
}
|
||||
const url = `${provider.authURL}?${stringifyQuery(query)}`;
|
||||
return launchWebAuthFlow({
|
||||
return browser.identity.launchWebAuthFlow({
|
||||
url,
|
||||
interactive
|
||||
})
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/* global API_METHODS usercss styleManager deepCopy openURL download URLS getTab */
|
||||
/* exports usercssHelper */
|
||||
/* global API_METHODS usercss styleManager deepCopy openURL download URLS */
|
||||
/* exported usercssHelper */
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const usercssHelper = (() => {
|
||||
const installCodeCache = {};
|
||||
const clearInstallCode = url => delete installCodeCache[url];
|
||||
|
@ -46,7 +45,7 @@ const usercssHelper = (() => {
|
|||
openInstallerPage(tabId, url, {code, inTab} = {}) {
|
||||
const newUrl = `${URLS.installUsercss}?updateUrl=${encodeURIComponent(url)}`;
|
||||
if (inTab) {
|
||||
getTab(tabId).then(tab =>
|
||||
browser.tabs.get(tabId).then(tab =>
|
||||
openURL({
|
||||
url: `${newUrl}&tabId=${tabId}`,
|
||||
active: tab.active,
|
||||
|
|
|
@ -19,90 +19,91 @@ self.createStyleInjector = self.INJECTED === 1 ? self.createStyleInjector : ({
|
|||
let isTransitionPatched;
|
||||
// will store the original method refs because the page can override them
|
||||
let creationDoc, createElement, createElementNS;
|
||||
|
||||
return {
|
||||
apply,
|
||||
clear,
|
||||
clearOrphans,
|
||||
remove,
|
||||
replace,
|
||||
toggle,
|
||||
|
||||
list,
|
||||
|
||||
apply(styleMap) {
|
||||
const styles = _styleMapToArray(styleMap);
|
||||
return (
|
||||
!styles.length ?
|
||||
Promise.resolve([]) :
|
||||
docRootObserver.evade(() => {
|
||||
if (!isTransitionPatched && isEnabled) {
|
||||
_applyTransitionPatch(styles);
|
||||
}
|
||||
return styles.map(_addUpdate);
|
||||
})
|
||||
).then(_emitUpdate);
|
||||
},
|
||||
|
||||
clear() {
|
||||
_addRemoveElements(false);
|
||||
list.length = 0;
|
||||
table.clear();
|
||||
_emitUpdate();
|
||||
},
|
||||
|
||||
clearOrphans() {
|
||||
for (const el of document.querySelectorAll(`style[id^="${PREFIX}"].stylus`)) {
|
||||
const id = el.id.slice(PREFIX.length);
|
||||
if (/^\d+$/.test(id) || id === PATCH_ID) {
|
||||
el.remove();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
_remove(id);
|
||||
_emitUpdate();
|
||||
},
|
||||
|
||||
replace(styleMap) {
|
||||
const styles = _styleMapToArray(styleMap);
|
||||
const added = new Set(styles.map(s => s.id));
|
||||
const removed = [];
|
||||
for (const style of list) {
|
||||
if (!added.has(style.id)) {
|
||||
removed.push(style.id);
|
||||
}
|
||||
}
|
||||
styles.forEach(_addUpdate);
|
||||
removed.forEach(_remove);
|
||||
_emitUpdate();
|
||||
},
|
||||
|
||||
toggle(enable) {
|
||||
if (isEnabled === enable) return;
|
||||
isEnabled = enable;
|
||||
if (!enable) _toggleObservers(false);
|
||||
_addRemoveElements(enable);
|
||||
if (enable) _toggleObservers(true);
|
||||
},
|
||||
};
|
||||
|
||||
function apply(styleMap) {
|
||||
const styles = _styleMapToArray(styleMap);
|
||||
return !styles.length ?
|
||||
Promise.resolve([]) :
|
||||
docRootObserver.evade(() => {
|
||||
if (!isTransitionPatched) _applyTransitionPatch(styles);
|
||||
const els = styles.map(_apply);
|
||||
_emitUpdate();
|
||||
return els;
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
for (const style of list) {
|
||||
style.el.remove();
|
||||
function _add(style) {
|
||||
const el = style.el = _createStyle(style.id, style.code);
|
||||
const i = list.findIndex(item => compare(item, style) > 0);
|
||||
table.set(style.id, style);
|
||||
if (isEnabled) {
|
||||
document.documentElement.insertBefore(el, i < 0 ? null : list[i].el);
|
||||
}
|
||||
list.length = 0;
|
||||
table.clear();
|
||||
_emitUpdate();
|
||||
list.splice(i < 0 ? list.length : i, 0, style);
|
||||
return el;
|
||||
}
|
||||
|
||||
function clearOrphans() {
|
||||
for (const el of document.querySelectorAll(`style[id^="${PREFIX}"].stylus`)) {
|
||||
const id = el.id.slice(PREFIX.length);
|
||||
if (/^\d+$/.test(id) || id === PATCH_ID) {
|
||||
function _addRemoveElements(add) {
|
||||
for (const {el} of list) {
|
||||
if (add) {
|
||||
document.documentElement.appendChild(el);
|
||||
} else {
|
||||
el.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function remove(id) {
|
||||
_remove(id);
|
||||
_emitUpdate();
|
||||
}
|
||||
|
||||
function replace(styleMap) {
|
||||
const styles = _styleMapToArray(styleMap);
|
||||
const added = new Set(styles.map(s => s.id));
|
||||
const removed = [];
|
||||
for (const style of list) {
|
||||
if (!added.has(style.id)) {
|
||||
removed.push(style.id);
|
||||
}
|
||||
}
|
||||
styles.forEach(_apply);
|
||||
removed.forEach(_remove);
|
||||
_emitUpdate();
|
||||
}
|
||||
|
||||
function toggle(_enabled) {
|
||||
if (isEnabled === _enabled) return;
|
||||
isEnabled = _enabled;
|
||||
for (const style of list) {
|
||||
style.el.disabled = !isEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
function _add(style) {
|
||||
const el = style.el = _createStyle(style.id, style.code);
|
||||
table.set(style.id, style);
|
||||
const nextIndex = list.findIndex(i => compare(i, style) > 0);
|
||||
if (nextIndex < 0) {
|
||||
document.documentElement.appendChild(el);
|
||||
list.push(style);
|
||||
} else {
|
||||
document.documentElement.insertBefore(el, list[nextIndex].el);
|
||||
list.splice(nextIndex, 0, style);
|
||||
}
|
||||
// moving an element resets its 'disabled' state
|
||||
el.disabled = !isEnabled;
|
||||
return el;
|
||||
}
|
||||
|
||||
function _apply(style) {
|
||||
function _addUpdate(style) {
|
||||
return table.has(style.id) ? _update(style) : _add(style);
|
||||
}
|
||||
|
||||
|
@ -151,15 +152,16 @@ self.createStyleInjector = self.INJECTED === 1 ? self.createStyleInjector : ({
|
|||
return el;
|
||||
}
|
||||
|
||||
function _emitUpdate() {
|
||||
if (!IS_OWN_PAGE && list.length) {
|
||||
docRewriteObserver.start();
|
||||
docRootObserver.start();
|
||||
} else {
|
||||
docRewriteObserver.stop();
|
||||
docRootObserver.stop();
|
||||
}
|
||||
function _toggleObservers(shouldStart) {
|
||||
const onOff = shouldStart && isEnabled ? 'start' : 'stop';
|
||||
docRewriteObserver[onOff]();
|
||||
docRootObserver[onOff]();
|
||||
}
|
||||
|
||||
function _emitUpdate(value) {
|
||||
_toggleObservers(!IS_OWN_PAGE && list.length);
|
||||
onUpdate();
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -193,11 +195,7 @@ self.createStyleInjector = self.INJECTED === 1 ? self.createStyleInjector : ({
|
|||
function _sort() {
|
||||
docRootObserver.evade(() => {
|
||||
list.sort(compare);
|
||||
for (const style of list) {
|
||||
// moving an element resets its 'disabled' state
|
||||
document.documentElement.appendChild(style.el);
|
||||
style.el.disabled = !isEnabled;
|
||||
}
|
||||
_addRemoveElements(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -241,13 +239,13 @@ self.createStyleInjector = self.INJECTED === 1 ? self.createStyleInjector : ({
|
|||
if (isChromePre65) {
|
||||
const oldEl = style.el;
|
||||
style.el = _createStyle(id, code);
|
||||
oldEl.parentNode.insertBefore(style.el, oldEl.nextSibling);
|
||||
oldEl.remove();
|
||||
if (isEnabled) {
|
||||
oldEl.parentNode.insertBefore(style.el, oldEl.nextSibling);
|
||||
oldEl.remove();
|
||||
}
|
||||
} else {
|
||||
style.el.textContent = code;
|
||||
}
|
||||
// https://github.com/openstyles/stylus/issues/693
|
||||
style.el.disabled = !isEnabled;
|
||||
}
|
||||
|
||||
function RewriteObserver(onChange) {
|
||||
|
|
|
@ -64,7 +64,6 @@
|
|||
<script src="vendor-overwrites/codemirror-addon/match-highlighter.js"></script>
|
||||
|
||||
<script src="js/polyfill.js"></script>
|
||||
<script src="js/promisify.js"></script>
|
||||
<script src="js/dom.js"></script>
|
||||
<script src="js/messaging.js"></script>
|
||||
<script src="js/prefs.js"></script>
|
||||
|
|
109
edit/beautify.js
109
edit/beautify.js
|
@ -1,8 +1,49 @@
|
|||
/* global loadScript css_beautify showHelp prefs t $ $create */
|
||||
/* exported beautify */
|
||||
/* global editor createHotkeyInput moveFocus CodeMirror */
|
||||
/* exported initBeautifyButton */
|
||||
'use strict';
|
||||
|
||||
function beautify(scope) {
|
||||
const HOTKEY_ID = 'editor.beautify.hotkey';
|
||||
|
||||
prefs.initializing.then(() => {
|
||||
CodeMirror.defaults.extraKeys[prefs.get(HOTKEY_ID) || ''] = 'beautify';
|
||||
CodeMirror.commands.beautify = cm => {
|
||||
// using per-section mode when code editor or applies-to block is focused
|
||||
const isPerSection = cm.display.wrapper.parentElement.contains(document.activeElement);
|
||||
beautify(isPerSection ? [cm] : editor.getEditors(), false);
|
||||
};
|
||||
});
|
||||
|
||||
prefs.subscribe([HOTKEY_ID], (key, value) => {
|
||||
const {extraKeys} = CodeMirror.defaults;
|
||||
for (const [key, cmd] of Object.entries(extraKeys)) {
|
||||
if (cmd === 'beautify') {
|
||||
delete extraKeys[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value) {
|
||||
extraKeys[value] = 'beautify';
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} btn - the button element shown in the UI
|
||||
* @param {function():CodeMirror[]} getScope
|
||||
*/
|
||||
function initBeautifyButton(btn, getScope) {
|
||||
btn.addEventListener('click', () => beautify(getScope()));
|
||||
btn.addEventListener('contextmenu', e => {
|
||||
e.preventDefault();
|
||||
beautify(getScope(), false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CodeMirror[]} scope
|
||||
* @param {?boolean} ui
|
||||
*/
|
||||
function beautify(scope, ui = true) {
|
||||
loadScript('/vendor-overwrites/beautify/beautify-css-mod.js')
|
||||
.then(() => {
|
||||
if (!window.css_beautify && window.exports) {
|
||||
|
@ -19,7 +60,41 @@ function beautify(scope) {
|
|||
}
|
||||
options.indent_size = tabs ? 1 : prefs.get('editor.tabSize');
|
||||
options.indent_char = tabs ? '\t' : ' ';
|
||||
if (ui) {
|
||||
createBeautifyUI(scope, options);
|
||||
}
|
||||
for (const cm of scope) {
|
||||
setTimeout(doBeautifyEditor, 0, cm, options);
|
||||
}
|
||||
}
|
||||
|
||||
function doBeautifyEditor(cm, options) {
|
||||
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]});
|
||||
}
|
||||
const {scrollX, scrollY} = window;
|
||||
cm.setSelections(selections);
|
||||
window.scrollTo(scrollX, scrollY);
|
||||
cm.beautifyChange[cm.changeGeneration()] = true;
|
||||
if (ui) {
|
||||
$('#help-popup button[role="close"]').disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createBeautifyUI(scope, options) {
|
||||
showHelp(t('styleBeautify'),
|
||||
$create([
|
||||
$create('.beautify-options', [
|
||||
|
@ -32,6 +107,10 @@ function beautify(scope) {
|
|||
$createLabeledCheckbox('preserve_newlines', 'styleBeautifyPreserveNewlines'),
|
||||
$createLabeledCheckbox('indent_conditional', 'styleBeautifyIndentConditional'),
|
||||
]),
|
||||
$create('p.beautify-hint', [
|
||||
$create('span', t('styleBeautifyHint') + '\u00A0'),
|
||||
createHotkeyInput(HOTKEY_ID, () => moveFocus($('#help-popup'), 1)),
|
||||
]),
|
||||
$create('.buttons', [
|
||||
$create('button', {
|
||||
attributes: {role: 'close'},
|
||||
|
@ -60,32 +139,6 @@ function beautify(scope) {
|
|||
|
||||
$('#help-popup').className = 'wide';
|
||||
|
||||
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]});
|
||||
}
|
||||
const {scrollX, scrollY} = window;
|
||||
cm.setSelections(selections);
|
||||
window.scrollTo(scrollX, scrollY);
|
||||
cm.beautifyChange[cm.changeGeneration()] = true;
|
||||
$('#help-popup button[role="close"]').disabled = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.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}));
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
outline: -webkit-focus-ring-color auto 5px;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
.CodeMirror-bookmark {
|
||||
background: linear-gradient(to right, currentColor, transparent);
|
||||
position: absolute;
|
||||
width: 2em;
|
||||
opacity: .5;
|
||||
}
|
||||
@supports (-moz-appearance:none) {
|
||||
/* restrict to FF */
|
||||
.CodeMirror-focused {
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
prefs.reset('editor.keyMap');
|
||||
}
|
||||
|
||||
const CM_BOOKMARK = 'CodeMirror-bookmark';
|
||||
const CM_BOOKMARK_GUTTER = CM_BOOKMARK + 'gutter';
|
||||
const defaults = {
|
||||
autoCloseBrackets: prefs.get('editor.autoCloseBrackets'),
|
||||
mode: 'css',
|
||||
|
@ -15,6 +17,7 @@
|
|||
lineWrapping: prefs.get('editor.lineWrapping'),
|
||||
foldGutter: true,
|
||||
gutters: [
|
||||
CM_BOOKMARK_GUTTER,
|
||||
'CodeMirror-linenumbers',
|
||||
'CodeMirror-foldgutter',
|
||||
...(prefs.get('editor.linter') ? ['CodeMirror-lint-markers'] : []),
|
||||
|
@ -102,92 +105,19 @@
|
|||
}
|
||||
|
||||
Object.assign(CodeMirror.mimeModes['text/css'].propertyKeywords, {
|
||||
// CSS Backgrounds and Borders Module L4
|
||||
'background-position-x': true,
|
||||
'background-position-y': true,
|
||||
|
||||
// CSS Logical Properties and Values L1
|
||||
'block-size': true,
|
||||
'border-block-color': true,
|
||||
'border-block-end': true,
|
||||
'border-block-end-color': true,
|
||||
'border-block-end-style': true,
|
||||
'border-block-end-width': true,
|
||||
'border-block-start': true,
|
||||
'border-block-start-color': true,
|
||||
'border-block-start-style': true,
|
||||
'border-block-start-width': true,
|
||||
'border-block-style': true,
|
||||
'border-block-width': true,
|
||||
'border-inline-color': true,
|
||||
'border-inline-end': true,
|
||||
'border-inline-end-color': true,
|
||||
'border-inline-end-style': true,
|
||||
'border-inline-end-width': true,
|
||||
'border-inline-start': true,
|
||||
'border-inline-start-color': true,
|
||||
'border-inline-start-style': true,
|
||||
'border-inline-start-width': true,
|
||||
'border-inline-style': true,
|
||||
'border-inline-width': true,
|
||||
'inline-size': true,
|
||||
'inset': true,
|
||||
'inset-block': true,
|
||||
'inset-block-end': true,
|
||||
'inset-block-start': true,
|
||||
'inset-inline': true,
|
||||
'inset-inline-end': true,
|
||||
'inset-inline-start': true,
|
||||
'margin-block': true,
|
||||
'margin-block-end': true,
|
||||
'margin-block-start': true,
|
||||
'margin-inline': true,
|
||||
'margin-inline-end': true,
|
||||
'margin-inline-start': true,
|
||||
'max-block-size': true,
|
||||
'max-inline-size': true,
|
||||
'min-block-size': true,
|
||||
'min-inline-size': true,
|
||||
'padding-block': true,
|
||||
'padding-block-end': true,
|
||||
'padding-block-start': true,
|
||||
'padding-inline': true,
|
||||
'padding-inline-end': true,
|
||||
'padding-inline-start': true,
|
||||
'text-align-all': true,
|
||||
|
||||
'contain': true,
|
||||
'mask-image': true,
|
||||
'mix-blend-mode': true,
|
||||
'overscroll-behavior': true,
|
||||
'rotate': true,
|
||||
'isolation': true,
|
||||
'zoom': true,
|
||||
|
||||
// https://www.w3.org/TR/css-round-display-1/
|
||||
'border-boundary': true,
|
||||
'shape': true,
|
||||
'shape-inside': true,
|
||||
'viewport-fit': true,
|
||||
|
||||
// nonstandard https://compat.spec.whatwg.org/
|
||||
'box-reflect': true,
|
||||
'text-fill-color': true,
|
||||
'text-stroke': true,
|
||||
'text-stroke-color': true,
|
||||
'text-stroke-width': true,
|
||||
// end
|
||||
});
|
||||
Object.assign(CodeMirror.mimeModes['text/css'].valueKeywords, {
|
||||
'isolate': true,
|
||||
'rect': true,
|
||||
'recto': true,
|
||||
'verso': true,
|
||||
});
|
||||
Object.assign(CodeMirror.mimeModes['text/css'].colorKeywords, {
|
||||
'darkgrey': true,
|
||||
'darkslategrey': true,
|
||||
'dimgrey': true,
|
||||
'grey': true,
|
||||
'lightgrey': true,
|
||||
'lightslategrey': true,
|
||||
'slategrey': true,
|
||||
|
@ -242,22 +172,27 @@
|
|||
CodeMirror.commands[name] = (...args) => editor[name](...args);
|
||||
}
|
||||
|
||||
// speedup: reuse the old folding marks
|
||||
// TODO: remove when https://github.com/codemirror/CodeMirror/pull/6010 is shipped in /vendor
|
||||
const {setGutterMarker} = CodeMirror.prototype;
|
||||
CodeMirror.prototype.setGutterMarker = function (line, gutterID, value) {
|
||||
const o = this.state.foldGutter.options;
|
||||
if (typeof o.indicatorOpen === 'string' ||
|
||||
typeof o.indicatorFolded === 'string') {
|
||||
const old = line.gutterMarkers && line.gutterMarkers[gutterID];
|
||||
// old className can contain other names set by CodeMirror so we'll use classList
|
||||
if (old && value && old.classList.contains(value.className) ||
|
||||
!old && !value) {
|
||||
return line;
|
||||
}
|
||||
const elBookmark = document.createElement('div');
|
||||
elBookmark.className = CM_BOOKMARK;
|
||||
elBookmark.textContent = '\u00A0';
|
||||
const clearMarker = function () {
|
||||
const line = this.lines[0];
|
||||
CodeMirror.TextMarker.prototype.clear.apply(this);
|
||||
if (!line.markedSpans.some(span => span.marker.sublimeBookmark)) {
|
||||
this.doc.setGutterMarker(line, CM_BOOKMARK_GUTTER, null);
|
||||
}
|
||||
return setGutterMarker.apply(this, arguments);
|
||||
};
|
||||
const {markText} = CodeMirror.prototype;
|
||||
Object.assign(CodeMirror.prototype, {
|
||||
markText() {
|
||||
const marker = markText.apply(this, arguments);
|
||||
if (marker.sublimeBookmark) {
|
||||
this.doc.setGutterMarker(marker.lines[0], CM_BOOKMARK_GUTTER, elBookmark.cloneNode(true));
|
||||
marker.clear = clearMarker;
|
||||
}
|
||||
return marker;
|
||||
},
|
||||
});
|
||||
|
||||
// CodeMirror convenience commands
|
||||
Object.assign(CodeMirror.commands, {
|
||||
|
@ -307,6 +242,7 @@ CodeMirror.hint && (() => {
|
|||
const RX_IMPORTANT = /(i(m(p(o(r(t(a(nt?)?)?)?)?)?)?)?)?(?=\b|\W|$)/iy;
|
||||
const RX_VAR_KEYWORD = /(^|[^-\w\u0080-\uFFFF])var\(/iy;
|
||||
const RX_END_OF_VAR = /[\s,)]|$/g;
|
||||
const RX_CONSUME_PROP = /[-\w]*\s*:\s?|$/y;
|
||||
|
||||
const originalHelper = CodeMirror.hint.css || (() => {});
|
||||
const helper = cm => {
|
||||
|
@ -372,7 +308,15 @@ CodeMirror.hint && (() => {
|
|||
}
|
||||
|
||||
if (!editor || !style || !style.includes(USO_VAR)) {
|
||||
return originalHelper(cm);
|
||||
// add ":" after a property name
|
||||
const res = originalHelper(cm);
|
||||
const state = res && cm.getTokenAt(pos).state.state;
|
||||
if (state === 'block' || state === 'maybeprop') {
|
||||
res.list = res.list.map(str => str + ': ');
|
||||
RX_CONSUME_PROP.lastIndex = res.to.ch;
|
||||
res.to.ch += RX_CONSUME_PROP.exec(text)[0].length;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// USO vars in usercss mode editor
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global CodeMirror showHelp cmFactory onDOMready $ $create prefs t */
|
||||
/* global CodeMirror showHelp cmFactory onDOMready $ prefs t createHotkeyInput */
|
||||
'use strict';
|
||||
|
||||
(() => {
|
||||
|
@ -62,46 +62,8 @@
|
|||
|
||||
function configureColorpicker(event) {
|
||||
event.preventDefault();
|
||||
const input = $create('input', {
|
||||
type: 'search',
|
||||
spellcheck: false,
|
||||
value: prefs.get('editor.colorpicker.hotkey'),
|
||||
onkeydown(event) {
|
||||
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
|
||||
prefs.set('editor.colorpicker.hotkey', '');
|
||||
},
|
||||
onpaste(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
const input = createHotkeyInput('editor.colorpicker.hotkey', () => {
|
||||
$('#help-popup .dismiss').onclick();
|
||||
});
|
||||
const popup = showHelp(t('helpKeyMapHotkey'), input);
|
||||
if (this instanceof Element) {
|
||||
|
|
|
@ -267,6 +267,10 @@ input:invalid {
|
|||
margin-top: 4em;
|
||||
}
|
||||
/************ section editor ***********/
|
||||
.CodeMirror-vscrollbar,
|
||||
.CodeMirror-hscrollbar {
|
||||
pointer-events: auto !important; /* FF bug */
|
||||
}
|
||||
.section-editor .section {
|
||||
margin: 0 0.7rem;
|
||||
padding: 1rem;
|
||||
|
@ -775,6 +779,11 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
|
|||
padding-left: 4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.beautify-hint {
|
||||
width: 0;
|
||||
min-width: 100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/************ single editor **************/
|
||||
.usercss body {
|
||||
|
|
23
edit/edit.js
23
edit/edit.js
|
@ -1,7 +1,7 @@
|
|||
/* global CodeMirror onDOMready prefs setupLivePrefs $ $$ $create t tHTML
|
||||
createSourceEditor queryTabs sessionStorageHash getOwnTab FIREFOX API tryCatch
|
||||
createSourceEditor sessionStorageHash getOwnTab FIREFOX API tryCatch
|
||||
closeCurrentTab messageBox debounce workerUtil
|
||||
beautify ignoreChromeError
|
||||
initBeautifyButton ignoreChromeError
|
||||
moveFocus msg createSectionsEditor rerouteHotkeys CODEMIRROR_THEMES */
|
||||
/* exported showCodeMirrorPopup editorWorker toggleContextMenuDelete */
|
||||
'use strict';
|
||||
|
@ -170,12 +170,21 @@ preinit();
|
|||
$('#heading').textContent = t(style.id ? 'editStyleHeading' : 'addStyleTitle');
|
||||
$('#name').placeholder = t(usercss ? 'usercssEditorNamePlaceholder' : 'styleMissingName');
|
||||
$('#name').title = usercss ? t('usercssReplaceTemplateName') : '';
|
||||
|
||||
$('#preview-label').classList.toggle('hidden', !style.id);
|
||||
|
||||
$('#beautify').onclick = () => beautify(editor.getEditors());
|
||||
initBeautifyButton($('#beautify'), () => editor.getEditors());
|
||||
const {onBoundsChanged} = chrome.windows || {};
|
||||
if (onBoundsChanged) {
|
||||
// * movement is reported even if the window wasn't resized
|
||||
// * fired just once when done so debounce is not needed
|
||||
onBoundsChanged.addListener(wnd => {
|
||||
// getting the current window id as it may change if the user attached/detached the tab
|
||||
chrome.windows.getCurrent(ownWnd => {
|
||||
if (wnd.id === ownWnd.id) rememberWindowSize();
|
||||
});
|
||||
});
|
||||
}
|
||||
window.addEventListener('resize', () => {
|
||||
debounce(rememberWindowSize, 100);
|
||||
if (!onBoundsChanged) debounce(rememberWindowSize, 100);
|
||||
detectLayout();
|
||||
});
|
||||
detectLayout();
|
||||
|
@ -217,7 +226,7 @@ function preinit() {
|
|||
}).observe(document, {subtree: true, childList: true});
|
||||
|
||||
if (chrome.windows) {
|
||||
queryTabs({currentWindow: true}).then(tabs => {
|
||||
browser.tabs.query({currentWindow: true}).then(tabs => {
|
||||
const windowId = tabs[0].windowId;
|
||||
if (prefs.get('openEditInWindow')) {
|
||||
if (
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
border: none;
|
||||
background-color: white;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
white-space: pre; /* issue #1000 */
|
||||
color: currentColor; /* use the current theme's color instead of UserAgent's CSS */
|
||||
flex: 1;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global CodeMirror focusAccessibility colorMimicry editor
|
||||
/* global CodeMirror focusAccessibility colorMimicry editor chromeLocal
|
||||
onDOMready $ $$ $create t debounce tryRegExp stringAsRegExp template */
|
||||
'use strict';
|
||||
|
||||
|
@ -915,7 +915,7 @@ onDOMready().then(() => {
|
|||
|
||||
|
||||
function readStorage() {
|
||||
chrome.storage.local.get('editor', ({editor = {}}) => {
|
||||
chromeLocal.getValue('editor').then((editor = {}) => {
|
||||
state.find = editor.find || '';
|
||||
state.replace = editor.replace || '';
|
||||
state.icase = editor.icase || state.icase;
|
||||
|
@ -924,14 +924,12 @@ onDOMready().then(() => {
|
|||
|
||||
|
||||
function writeStorage() {
|
||||
chrome.storage.local.get('editor', ({editor}) =>
|
||||
chrome.storage.local.set({
|
||||
editor: Object.assign(editor || {}, {
|
||||
find: state.find,
|
||||
replace: state.replace,
|
||||
icase: state.icase,
|
||||
})
|
||||
}));
|
||||
chromeLocal.getValue('editor').then((editor = {}) =>
|
||||
chromeLocal.setValue('editor', Object.assign(editor, {
|
||||
find: state.find,
|
||||
replace: state.replace,
|
||||
icase: state.icase,
|
||||
})));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global showHelp $ $create tryRegExp queryTabs URLS t template openURL */
|
||||
/* global showHelp $ $create tryRegExp URLS t template openURL */
|
||||
/* exported regExpTester */
|
||||
'use strict';
|
||||
|
||||
|
@ -66,7 +66,7 @@ const regExpTester = (() => {
|
|||
return rxData;
|
||||
});
|
||||
const getMatchInfo = m => m && {text: m[0], pos: m.index};
|
||||
queryTabs({}).then(tabs => {
|
||||
browser.tabs.query({}).then(tabs => {
|
||||
const supported = tabs.map(tab => tab.url)
|
||||
.filter(url => URLS.supported(url));
|
||||
const unique = [...new Set(supported).values()];
|
||||
|
|
|
@ -12,6 +12,7 @@ const rerouteHotkeys = (() => {
|
|||
'toggleEditorFocus',
|
||||
'find', 'findNext', 'findPrev', 'replace', 'replaceAll',
|
||||
'colorpicker',
|
||||
'beautify',
|
||||
]);
|
||||
|
||||
return rerouteHotkeys;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* global template cmFactory $ propertyToCss CssToProperty linter regExpTester
|
||||
FIREFOX toggleContextMenuDelete beautify showHelp t tryRegExp */
|
||||
FIREFOX toggleContextMenuDelete initBeautifyButton showHelp t tryRegExp */
|
||||
/* exported createSection */
|
||||
'use strict';
|
||||
|
||||
|
@ -94,6 +94,7 @@ function createSection({
|
|||
const cm = cmFactory.create(wrapper => {
|
||||
el.insertBefore(wrapper, $('.code-label', el).nextSibling);
|
||||
}, {value: originalSection.code});
|
||||
el.CodeMirror = cm; // used by getAssociatedEditor
|
||||
|
||||
const changeListeners = new Set();
|
||||
|
||||
|
@ -196,12 +197,12 @@ function createSection({
|
|||
$('.clone-section', el).addEventListener('click', () => insertSectionAfter(getModel(), section));
|
||||
$('.move-section-up', el).addEventListener('click', () => moveSectionUp(section));
|
||||
$('.move-section-down', el).addEventListener('click', () => moveSectionDown(section));
|
||||
$('.beautify-section', el).addEventListener('click', () => beautify([cm]));
|
||||
$('.restore-section', el).addEventListener('click', () => restoreSection(section));
|
||||
$('.test-regexp', el).addEventListener('click', () => {
|
||||
regExpTester.toggle();
|
||||
updateRegexpTester();
|
||||
});
|
||||
initBeautifyButton($('.beautify-section', el), () => [cm]);
|
||||
}
|
||||
|
||||
function handleKeydown(cm, event) {
|
||||
|
|
|
@ -34,7 +34,8 @@ function createSectionsEditor({style, onTitleChanged}) {
|
|||
$('#from-mozilla').addEventListener('click', () => showMozillaFormatImport());
|
||||
$('#save-button').addEventListener('click', saveStyle);
|
||||
|
||||
document.addEventListener('wheel', scrollEntirePageOnCtrlShift);
|
||||
document.addEventListener('wheel', scrollEntirePageOnCtrlShift, {passive: false});
|
||||
CodeMirror.defaults.extraKeys['Shift-Ctrl-Wheel'] = 'scrollWindow';
|
||||
|
||||
if (!FIREFOX) {
|
||||
$$([
|
||||
|
@ -154,9 +155,7 @@ function createSectionsEditor({style, onTitleChanged}) {
|
|||
function closestVisible(nearbyElement) {
|
||||
const cm =
|
||||
nearbyElement instanceof CodeMirror ? nearbyElement :
|
||||
nearbyElement instanceof Node &&
|
||||
(nearbyElement.closest('#sections > .section') || {}).CodeMirror ||
|
||||
getLastActivatedEditor();
|
||||
nearbyElement instanceof Node && getAssociatedEditor(nearbyElement) || getLastActivatedEditor();
|
||||
if (nearbyElement instanceof Node && cm) {
|
||||
const {left, top} = nearbyElement.getBoundingClientRect();
|
||||
const bounds = cm.display.wrapper.getBoundingClientRect();
|
||||
|
@ -228,6 +227,15 @@ function createSectionsEditor({style, onTitleChanged}) {
|
|||
}
|
||||
}
|
||||
|
||||
function getAssociatedEditor(nearbyElement) {
|
||||
for (let el = nearbyElement; el; el = el.parentElement) {
|
||||
// added by createSection
|
||||
if (el.CodeMirror) {
|
||||
return el.CodeMirror;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEditors() {
|
||||
return sections.filter(s => !s.isRemoved()).map(s => s.cm);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ 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];
|
||||
|
|
52
edit/util.js
52
edit/util.js
|
@ -1,4 +1,5 @@
|
|||
/* exported dirtyReporter memoize clipString sectionsToMozFormat */
|
||||
/* global CodeMirror $create prefs */
|
||||
/* exported dirtyReporter memoize clipString sectionsToMozFormat createHotkeyInput */
|
||||
'use strict';
|
||||
|
||||
function dirtyReporter() {
|
||||
|
@ -135,3 +136,52 @@ function memoize(fn) {
|
|||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!string} prefId
|
||||
* @param {?function(isEnter:boolean)} onDone
|
||||
*/
|
||||
function createHotkeyInput(prefId, onDone = () => {}) {
|
||||
return $create('input', {
|
||||
type: 'search',
|
||||
spellcheck: false,
|
||||
value: prefs.get(prefId),
|
||||
onkeydown(event) {
|
||||
const key = CodeMirror.keyName(event);
|
||||
if (key === 'Tab' || key === 'Shift-Tab') {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
switch (key) {
|
||||
case 'Enter':
|
||||
if (this.checkValidity()) onDone(true);
|
||||
return;
|
||||
case 'Esc':
|
||||
onDone(false);
|
||||
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(prefId, key);
|
||||
},
|
||||
oninput() {
|
||||
// fired on pressing "x" to clear the field
|
||||
prefs.set(prefId, '');
|
||||
},
|
||||
onpaste(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
<link href="install-usercss/install-usercss.css" rel="stylesheet">
|
||||
|
||||
<script src="js/polyfill.js"></script>
|
||||
<script src="js/promisify.js"></script>
|
||||
<script src="js/msg.js"></script>
|
||||
<script src="js/messaging.js"></script>
|
||||
<script src="js/prefs.js"></script>
|
||||
|
|
|
@ -405,13 +405,9 @@
|
|||
}
|
||||
});
|
||||
port.onDisconnect.addListener(() => {
|
||||
chrome.tabs.get(tabId, tab => {
|
||||
if (chrome.runtime.lastError) {
|
||||
closeCurrentTab();
|
||||
} else if (tab.url === initialUrl) {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
browser.tabs.get(tabId)
|
||||
.then(tab => tab.url === initialUrl && location.reload())
|
||||
.catch(closeCurrentTab);
|
||||
});
|
||||
return ({timer = true} = {}) => new Promise((resolve, reject) => {
|
||||
const id = performance.now();
|
||||
|
|
21
js/dom.js
21
js/dom.js
|
@ -85,6 +85,27 @@ onDOMready().then(() => {
|
|||
|
||||
// set language for CSS :lang and [FF-only] hyphenation
|
||||
document.documentElement.setAttribute('lang', chrome.i18n.getUILanguage());
|
||||
// avoid adding # to the page URL when clicking dummy links
|
||||
document.addEventListener('click', e => {
|
||||
if (e.target.closest('a[href="#"]')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
// update inputs on mousewheel when focused
|
||||
document.addEventListener('wheel', event => {
|
||||
const el = document.activeElement;
|
||||
if (!el || el !== event.target && !el.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
if (el.tagName === 'SELECT') {
|
||||
el.selectedIndex = Math.max(0, Math.min(el.length - 1, el.selectedIndex + Math.sign(event.deltaY)));
|
||||
event.preventDefault();
|
||||
}
|
||||
event.stopImmediatePropagation();
|
||||
}, {
|
||||
capture: true,
|
||||
passive: false,
|
||||
});
|
||||
|
||||
function onDOMready() {
|
||||
if (document.readyState !== 'loading') {
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
/* exported getTab getActiveTab onTabReady stringAsRegExp openURL ignoreChromeError
|
||||
getStyleWithNoCode tryRegExp sessionStorageHash download deepEqual
|
||||
closeCurrentTab capitalize CHROME_HAS_BORDER_BUG */
|
||||
/* global promisify */
|
||||
/* global promisifyChrome */
|
||||
'use strict';
|
||||
|
||||
const CHROME = Boolean(chrome.app) && parseInt(navigator.userAgent.match(/Chrom\w+\/(?:\d+\.){2}(\d+)|$/)[1]);
|
||||
const CHROME = Boolean(chrome.app) && parseInt(navigator.userAgent.match(/Chrom\w+\/(\d+)|$/)[1]);
|
||||
const OPERA = Boolean(chrome.app) && parseFloat(navigator.userAgent.match(/\bOPR\/(\d+\.\d+)|$/)[1]);
|
||||
const VIVALDI = Boolean(chrome.app) && navigator.userAgent.includes('Vivaldi');
|
||||
// FIXME: who use this?
|
||||
// const ANDROID = !chrome.windows;
|
||||
let FIREFOX = !chrome.app && parseFloat(navigator.userAgent.match(/\bFirefox\/(\d+\.\d+)|$/)[1]);
|
||||
|
||||
// see PR #781
|
||||
const CHROME_HAS_BORDER_BUG = CHROME >= 3167 && CHROME <= 3704;
|
||||
const CHROME_HAS_BORDER_BUG = CHROME >= 62 && CHROME <= 74;
|
||||
|
||||
if (!CHROME && !chrome.browserAction.openPopup) {
|
||||
// in FF pre-57 legacy addons can override useragent so we assume the worst
|
||||
|
@ -62,7 +60,7 @@ const URLS = {
|
|||
|
||||
// Chrome 61.0.3161+ doesn't run content scripts on NTP https://crrev.com/2978953002/
|
||||
// TODO: remove when "minimum_chrome_version": "61" or higher
|
||||
chromeProtectsNTP: CHROME >= 3161,
|
||||
chromeProtectsNTP: CHROME >= 61,
|
||||
|
||||
userstylesOrgJson: 'https://userstyles.org/styles/chrome/',
|
||||
|
||||
|
@ -95,33 +93,20 @@ if (IS_BG) {
|
|||
// Object.defineProperty(window, 'localStorage', {value: {}});
|
||||
// Object.defineProperty(window, 'sessionStorage', {value: {}});
|
||||
|
||||
const createTab = promisify(chrome.tabs.create.bind(chrome.tabs));
|
||||
const queryTabs = promisify(chrome.tabs.query.bind(chrome.tabs));
|
||||
const updateTab = promisify(chrome.tabs.update.bind(chrome.tabs));
|
||||
const moveTabs = promisify(chrome.tabs.move.bind(chrome.tabs));
|
||||
|
||||
// Android doesn't have chrome.windows
|
||||
const updateWindow = chrome.windows && promisify(chrome.windows.update.bind(chrome.windows));
|
||||
const createWindow = chrome.windows && promisify(chrome.windows.create.bind(chrome.windows));
|
||||
promisifyChrome({
|
||||
tabs: ['create', 'get', 'getCurrent', 'move', 'query', 'update'],
|
||||
windows: ['create', 'update'], // Android doesn't have chrome.windows
|
||||
});
|
||||
// FF57+ supports openerTabId, but not in Android
|
||||
// (detecting FF57 by the feature it added, not navigator.ua which may be spoofed in about:config)
|
||||
const openerTabIdSupported = (!FIREFOX || window.AbortController) && chrome.windows != null;
|
||||
|
||||
function getTab(id) {
|
||||
return new Promise(resolve =>
|
||||
chrome.tabs.get(id, tab =>
|
||||
!chrome.runtime.lastError && resolve(tab)));
|
||||
}
|
||||
|
||||
|
||||
function getOwnTab() {
|
||||
return new Promise(resolve =>
|
||||
chrome.tabs.getCurrent(tab => resolve(tab)));
|
||||
return browser.tabs.getCurrent();
|
||||
}
|
||||
|
||||
|
||||
function getActiveTab() {
|
||||
return queryTabs({currentWindow: true, active: true})
|
||||
return browser.tabs.query({currentWindow: true, active: true})
|
||||
.then(tabs => tabs[0]);
|
||||
}
|
||||
|
||||
|
@ -142,7 +127,7 @@ function urlToMatchPattern(url, ignoreSearch) {
|
|||
|
||||
function findExistingTab({url, currentWindow, ignoreHash = true, ignoreSearch = false}) {
|
||||
url = new URL(url);
|
||||
return queryTabs({url: urlToMatchPattern(url, ignoreSearch), currentWindow})
|
||||
return browser.tabs.query({url: urlToMatchPattern(url, ignoreSearch), currentWindow})
|
||||
// FIXME: is tab.url always normalized?
|
||||
.then(tabs => tabs.find(matchTab));
|
||||
|
||||
|
@ -193,8 +178,8 @@ function openURL({
|
|||
url: url !== tab.url && url.includes('#') ? url : undefined,
|
||||
});
|
||||
}
|
||||
if (newWindow && createWindow) {
|
||||
return createWindow(Object.assign({url}, windowPosition))
|
||||
if (newWindow && browser.windows) {
|
||||
return browser.windows.create(Object.assign({url}, windowPosition))
|
||||
.then(wnd => wnd.tabs[0]);
|
||||
}
|
||||
return getActiveTab().then((activeTab = {url: ''}) =>
|
||||
|
@ -207,7 +192,7 @@ function openURL({
|
|||
if (id != null && !openerTab.incognito && openerTabIdSupported) {
|
||||
options.openerTabId = id;
|
||||
}
|
||||
return createTab(options);
|
||||
return browser.tabs.create(options);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,9 +219,9 @@ function activateTab(tab, {url, index, openerTabId} = {}) {
|
|||
options.openerTabId = openerTabId;
|
||||
}
|
||||
return Promise.all([
|
||||
updateTab(tab.id, options),
|
||||
updateWindow && updateWindow(tab.windowId, {focused: true}),
|
||||
index != null && moveTabs(tab.id, {index})
|
||||
browser.tabs.update(tab.id, options),
|
||||
browser.windows && browser.windows.update(tab.windowId, {focused: true}),
|
||||
index != null && browser.tabs.move(tab.id, {index})
|
||||
])
|
||||
.then(() => tab);
|
||||
}
|
||||
|
@ -381,7 +366,8 @@ function download(url, {
|
|||
body,
|
||||
responseType = 'text',
|
||||
requiredStatusCode = 200,
|
||||
timeout = 10e3,
|
||||
timeout = 10e3, // connection timeout
|
||||
loadTimeout = 2 * 60e3, // data transfer timeout (counted from the first remote response)
|
||||
headers = {
|
||||
'Content-type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
|
@ -398,23 +384,41 @@ function download(url, {
|
|||
const usoVars = [];
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr;
|
||||
const u = new URL(collapseUsoVars(url));
|
||||
if (u.protocol === 'file:' && FIREFOX) {
|
||||
const onTimeout = () => {
|
||||
if (xhr) xhr.abort();
|
||||
reject(new Error('Timeout fetching ' + u.href));
|
||||
};
|
||||
let timer = setTimeout(onTimeout, timeout);
|
||||
const switchTimer = () => {
|
||||
clearTimeout(timer);
|
||||
timer = loadTimeout && setTimeout(onTimeout, loadTimeout);
|
||||
};
|
||||
if (u.protocol === 'file:' && FIREFOX) { // TODO: maybe remove this since FF68+ can't do it anymore
|
||||
// https://stackoverflow.com/questions/42108782/firefox-webextensions-get-local-files-content-by-path
|
||||
// FIXME: add FetchController when it is available.
|
||||
const timer = setTimeout(reject, timeout, new Error('Timeout fetching ' + u.href));
|
||||
fetch(u.href, {mode: 'same-origin'})
|
||||
.then(r => {
|
||||
clearTimeout(timer);
|
||||
switchTimer();
|
||||
return r.status === 200 ? r.text() : Promise.reject(r.status);
|
||||
})
|
||||
.catch(reject)
|
||||
.then(resolve);
|
||||
.then(text => {
|
||||
clearTimeout(timer);
|
||||
resolve(text);
|
||||
});
|
||||
return;
|
||||
}
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.timeout = timeout;
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState >= XMLHttpRequest.HEADERS_RECEIVED) {
|
||||
xhr.onreadystatechange = null;
|
||||
switchTimer();
|
||||
}
|
||||
};
|
||||
xhr.onloadend = event => {
|
||||
clearTimeout(timer);
|
||||
if (event.type !== 'error' && (
|
||||
xhr.status === requiredStatusCode || !requiredStatusCode ||
|
||||
u.protocol === 'file:')) {
|
||||
|
|
24
js/msg.js
24
js/msg.js
|
@ -1,12 +1,12 @@
|
|||
/* global promisify deepCopy */
|
||||
/* global promisifyChrome deepCopy */
|
||||
// deepCopy is only used if the script is executed in extension pages.
|
||||
'use strict';
|
||||
|
||||
self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
||||
const runtimeSend = promisify(chrome.runtime.sendMessage.bind(chrome.runtime));
|
||||
const tabSend = chrome.tabs && promisify(chrome.tabs.sendMessage.bind(chrome.tabs));
|
||||
const tabQuery = chrome.tabs && promisify(chrome.tabs.query.bind(chrome.tabs));
|
||||
|
||||
promisifyChrome({
|
||||
runtime: ['sendMessage'],
|
||||
tabs: ['sendMessage', 'query'],
|
||||
});
|
||||
const isBg = chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() === window;
|
||||
if (isBg) {
|
||||
window._msg = {
|
||||
|
@ -49,19 +49,21 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
|||
}
|
||||
}
|
||||
if (chrome.runtime.getBackgroundPage) {
|
||||
return promisify(chrome.runtime.getBackgroundPage.bind(chrome.runtime))()
|
||||
.catch(() => null);
|
||||
promisifyChrome({
|
||||
runtime: ['getBackgroundPage'],
|
||||
});
|
||||
return browser.runtime.getBackgroundPage().catch(() => null);
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
function send(data, target = 'extension') {
|
||||
const message = {data, target};
|
||||
return runtimeSend(message).then(unwrapData);
|
||||
return browser.runtime.sendMessage(message).then(unwrapData);
|
||||
}
|
||||
|
||||
function sendTab(tabId, data, options, target = 'tab') {
|
||||
return tabSend(tabId, {data, target}, options)
|
||||
return browser.tabs.sendMessage(tabId, {data, target}, options)
|
||||
.then(unwrapData);
|
||||
}
|
||||
|
||||
|
@ -99,7 +101,7 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
|||
}
|
||||
|
||||
function broadcastTab(data, filter, options, ignoreExtension = false, target = 'tab') {
|
||||
return tabQuery({})
|
||||
return browser.tabs.query({})
|
||||
// TODO: send to activated tabs first?
|
||||
.then(tabs => {
|
||||
const requests = [];
|
||||
|
@ -123,7 +125,7 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
|||
const message = {data: dataObj, target};
|
||||
if (tab && tab.id) {
|
||||
requests.push(
|
||||
tabSend(tab.id, message, options)
|
||||
browser.tabs.sendMessage(tab.id, message, options)
|
||||
.then(unwrapData)
|
||||
.catch(ignoreError)
|
||||
);
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
// eslint-disable-next-line no-unused-expressions
|
||||
self.INJECTED !== 1 && (() => {
|
||||
|
||||
// this part runs in workers, content scripts, our extension pages
|
||||
|
||||
if (!Object.entries) {
|
||||
Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]]);
|
||||
}
|
||||
|
@ -10,9 +12,38 @@ self.INJECTED !== 1 && (() => {
|
|||
Object.values = obj => Object.keys(obj).map(k => obj[k]);
|
||||
}
|
||||
|
||||
// the above was shared by content scripts and workers,
|
||||
// the rest is only needed for our extension pages
|
||||
if (!self.chrome || !self.chrome.tabs) return;
|
||||
// don't use self.chrome. It is undefined in Firefox
|
||||
if (typeof chrome !== 'object') return;
|
||||
// the rest is for content scripts and our extension pages
|
||||
|
||||
self.browser = polyfillBrowser();
|
||||
|
||||
/* Promisifies the specified `chrome` methods into `browser`.
|
||||
The definitions is an object like this: {
|
||||
'storage.sync': ['get', 'set'], // if deeper than one level, combine the path via `.`
|
||||
windows: ['create', 'update'], // items and sub-objects will only be created if present in `chrome`
|
||||
} */
|
||||
self.promisifyChrome = definitions => {
|
||||
for (const [scopeName, methods] of Object.entries(definitions)) {
|
||||
const path = scopeName.split('.');
|
||||
const src = path.reduce((obj, p) => obj && obj[p], chrome);
|
||||
if (!src) continue;
|
||||
const dst = path.reduce((obj, p) => obj[p] || (obj[p] = {}), browser);
|
||||
for (const name of methods) {
|
||||
const fn = src[name];
|
||||
if (!fn || dst[name] && !dst[name].isTrap) continue;
|
||||
dst[name] = (...args) => new Promise((resolve, reject) =>
|
||||
fn.call(src, ...args, (...results) =>
|
||||
chrome.runtime.lastError ?
|
||||
reject(chrome.runtime.lastError) :
|
||||
resolve(results.length <= 1 ? results[0] : results)));
|
||||
// a couple of callbacks have 2 parameters (we don't use those methods, but just in case)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!chrome.tabs) return;
|
||||
// the rest is for our extension pages
|
||||
|
||||
if (typeof document === 'object') {
|
||||
const ELEMENT_METH = {
|
||||
|
@ -75,4 +106,27 @@ self.INJECTED !== 1 && (() => {
|
|||
} catch (err) {
|
||||
Object.defineProperty(self, 'sessionStorage', {value: {}});
|
||||
}
|
||||
|
||||
function polyfillBrowser() {
|
||||
if (typeof browser === 'object' && browser.runtime) {
|
||||
return browser;
|
||||
}
|
||||
return createTrap(chrome, null);
|
||||
|
||||
function createTrap(base, parent) {
|
||||
const target = typeof base === 'function' ? () => {} : {};
|
||||
target.isTrap = true;
|
||||
return new Proxy(target, {
|
||||
get: (target, prop) => {
|
||||
if (target[prop]) return target[prop];
|
||||
if (base[prop] && (typeof base[prop] === 'object' || typeof base[prop] === 'function')) {
|
||||
target[prop] = createTrap(base[prop], base);
|
||||
return target[prop];
|
||||
}
|
||||
return base[prop];
|
||||
},
|
||||
apply: (target, thisArg, args) => base.apply(parent, args)
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
12
js/prefs.js
12
js/prefs.js
|
@ -1,4 +1,4 @@
|
|||
/* global promisify */
|
||||
/* global promisifyChrome */
|
||||
'use strict';
|
||||
|
||||
self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
||||
|
@ -63,6 +63,7 @@ self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
|||
end_with_newline: false,
|
||||
indent_conditional: true,
|
||||
},
|
||||
'editor.beautify.hotkey': '',
|
||||
'editor.lintDelay': 300, // lint gutter marker update delay, ms
|
||||
'editor.linter': 'csslint', // 'csslint' or 'stylelint' or ''
|
||||
'editor.lintReportDelay': 500, // lint report update delay, ms
|
||||
|
@ -110,10 +111,11 @@ self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
|||
specific: new Map(),
|
||||
};
|
||||
|
||||
const syncSet = promisify(chrome.storage.sync.set.bind(chrome.storage.sync));
|
||||
const syncGet = promisify(chrome.storage.sync.get.bind(chrome.storage.sync));
|
||||
promisifyChrome({
|
||||
'storage.sync': ['get', 'set'],
|
||||
});
|
||||
|
||||
const initializing = syncGet('settings')
|
||||
const initializing = browser.storage.sync.get('settings')
|
||||
.then(result => {
|
||||
if (result.settings) {
|
||||
setAll(result.settings, true);
|
||||
|
@ -240,7 +242,7 @@ self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
|||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
timer = null;
|
||||
syncSet({settings: values})
|
||||
browser.storage.sync.set({settings: values})
|
||||
.then(resolve, reject);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
'use strict';
|
||||
/*
|
||||
Convert chrome APIs into promises. Example:
|
||||
|
||||
const storageSyncGet = promisify(chrome.storage.sync.get.bind(chrome.storage.sync));
|
||||
storageSyncGet(['key']).then(result => {...});
|
||||
|
||||
*/
|
||||
self.promisify = self.INJECTED === 1 ? self.promisify : fn =>
|
||||
(...args) =>
|
||||
new Promise((resolve, reject) => {
|
||||
fn(...args, (...result) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
reject(chrome.runtime.lastError);
|
||||
return;
|
||||
}
|
||||
resolve(
|
||||
result.length === 0 ? undefined :
|
||||
result.length === 1 ? result[0] : result
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,7 +1,12 @@
|
|||
/* global loadScript tryJSONparse */
|
||||
/* global loadScript tryJSONparse promisifyChrome */
|
||||
/* exported chromeLocal chromeSync */
|
||||
'use strict';
|
||||
|
||||
promisifyChrome({
|
||||
'storage.local': ['get', 'remove', 'set'],
|
||||
'storage.sync': ['get', 'remove', 'set'],
|
||||
});
|
||||
|
||||
const [chromeLocal, chromeSync] = (() => {
|
||||
return [
|
||||
createWrapper('local'),
|
||||
|
@ -9,11 +14,11 @@ const [chromeLocal, chromeSync] = (() => {
|
|||
];
|
||||
|
||||
function createWrapper(name) {
|
||||
const storage = chrome.storage[name];
|
||||
const storage = browser.storage[name];
|
||||
const wrapper = {
|
||||
get: data => new Promise(resolve => storage.get(data, resolve)),
|
||||
set: data => new Promise(resolve => storage.set(data, () => resolve(data))),
|
||||
remove: data => new Promise(resolve => storage.remove(data, resolve)),
|
||||
get: storage.get.bind(storage),
|
||||
set: data => storage.set(data).then(() => data),
|
||||
remove: storage.remove.bind(storage),
|
||||
|
||||
/**
|
||||
* @param {String} key
|
||||
|
|
|
@ -6,7 +6,7 @@ const workerUtil = (() => {
|
|||
const loadedScripts = new Set();
|
||||
return {createWorker, createAPI, loadScript, cloneError};
|
||||
|
||||
function createWorker({url, lifeTime = 30}) {
|
||||
function createWorker({url, lifeTime = 300}) {
|
||||
let worker;
|
||||
let id;
|
||||
let timer;
|
||||
|
|
|
@ -147,7 +147,6 @@
|
|||
</template>
|
||||
|
||||
<script src="js/polyfill.js"></script>
|
||||
<script src="js/promisify.js"></script>
|
||||
<script src="js/dom.js"></script>
|
||||
<script src="js/messaging.js"></script>
|
||||
<script src="js/prefs.js"></script>
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
/* global messageBox styleSectionsEqual API onDOMready
|
||||
tryJSONparse scrollElementIntoView $ $$ API $create t animateElement
|
||||
styleJSONseemsValid */
|
||||
/* exported bulkChangeQueue bulkChangeTime */
|
||||
'use strict';
|
||||
|
||||
const STYLISH_DUMP_FILE_EXT = '.txt';
|
||||
const STYLUS_BACKUP_FILE_EXT = '.json';
|
||||
|
||||
let bulkChangeQueue = [];
|
||||
let bulkChangeTime = 0;
|
||||
|
||||
onDOMready().then(() => {
|
||||
$('#file-all-styles').onclick = event => {
|
||||
event.preventDefault();
|
||||
|
@ -136,6 +140,8 @@ function importFromString(jsonString) {
|
|||
items.push({info, item});
|
||||
}
|
||||
});
|
||||
bulkChangeQueue.length = 0;
|
||||
bulkChangeTime = performance.now();
|
||||
return API.importManyStyles(items.map(i => i.item))
|
||||
.then(styles => {
|
||||
for (let i = 0; i < styles.length; i++) {
|
||||
|
|
|
@ -73,18 +73,22 @@ onDOMready().then(() => {
|
|||
}
|
||||
|
||||
function maybeRefocus(event) {
|
||||
if (event.altKey || event.ctrlKey || event.metaKey ||
|
||||
event.target.matches('[type="text"], [type="search"], [type="number"]') ||
|
||||
$('#message-box')) {
|
||||
if (event.altKey || event.metaKey || $('#message-box')) {
|
||||
return;
|
||||
}
|
||||
const inTextInput = event.target.matches('[type=text], [type=search], [type=number]');
|
||||
const {which: k, key} = event;
|
||||
// focus search field on "/" key
|
||||
if (key === '/' || !key && k === 191 && !event.shiftKey) {
|
||||
// focus search field on "/" or Ctrl-F key
|
||||
if (event.ctrlKey
|
||||
? (event.code === 'KeyF' || !event.code && k === 70) && !event.shiftKey
|
||||
: (key === '/' || !key && k === 191 && !event.shiftKey) && !inTextInput) {
|
||||
event.preventDefault();
|
||||
$('#search').focus();
|
||||
return;
|
||||
}
|
||||
if (event.ctrlKey || inTextInput) {
|
||||
return;
|
||||
}
|
||||
const time = performance.now();
|
||||
if (
|
||||
// 0-9
|
||||
|
|
|
@ -8,6 +8,7 @@ global messageBox getStyleWithNoCode
|
|||
URLS enforceInputRange t tWordBreak formatDate
|
||||
getOwnTab getActiveTab openURL animateElement sessionStorageHash debounce
|
||||
scrollElementIntoView CHROME VIVALDI FIREFOX router
|
||||
bulkChangeTime:true bulkChangeQueue
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
@ -16,6 +17,8 @@ let installed;
|
|||
const ENTRY_ID_PREFIX_RAW = 'style-';
|
||||
const ENTRY_ID_PREFIX = '#' + ENTRY_ID_PREFIX_RAW;
|
||||
|
||||
const BULK_THROTTLE_MS = 100;
|
||||
|
||||
const newUI = {
|
||||
enabled: prefs.get('manage.newUI'),
|
||||
favicons: prefs.get('manage.newUI.favicons'),
|
||||
|
@ -62,11 +65,13 @@ function onRuntimeMessage(msg) {
|
|||
switch (msg.method) {
|
||||
case 'styleUpdated':
|
||||
case 'styleAdded':
|
||||
API.getStyle(msg.style.id, true)
|
||||
.then(style => handleUpdate(style, msg));
|
||||
break;
|
||||
case 'styleDeleted':
|
||||
handleDelete(msg.style.id);
|
||||
bulkChangeQueue.push(msg);
|
||||
if (performance.now() - bulkChangeTime < BULK_THROTTLE_MS) {
|
||||
debounce(handleBulkChange, BULK_THROTTLE_MS);
|
||||
} else {
|
||||
handleBulkChange();
|
||||
}
|
||||
break;
|
||||
case 'styleApply':
|
||||
case 'styleReplaceAll':
|
||||
|
@ -449,6 +454,8 @@ Object.assign(handleEvent, {
|
|||
API.deleteStyle(id);
|
||||
}
|
||||
});
|
||||
const deleteButton = $('#message-box-buttons > button');
|
||||
if (deleteButton) deleteButton.removeAttribute('data-focused-via-click');
|
||||
},
|
||||
|
||||
external(event) {
|
||||
|
@ -529,6 +536,26 @@ Object.assign(handleEvent, {
|
|||
});
|
||||
|
||||
|
||||
function handleBulkChange() {
|
||||
for (const msg of bulkChangeQueue) {
|
||||
const {id} = msg.style;
|
||||
if (msg.method === 'styleDeleted') {
|
||||
handleDelete(id);
|
||||
bulkChangeTime = performance.now();
|
||||
} else {
|
||||
handleUpdateForId(id, msg);
|
||||
}
|
||||
}
|
||||
bulkChangeQueue.length = 0;
|
||||
}
|
||||
|
||||
function handleUpdateForId(id, opts) {
|
||||
return API.getStyle(id, true).then(style => {
|
||||
handleUpdate(style, opts);
|
||||
bulkChangeTime = performance.now();
|
||||
});
|
||||
}
|
||||
|
||||
function handleUpdate(style, {reason, method} = {}) {
|
||||
if (reason === 'editPreview' || reason === 'editPreviewEnd') return;
|
||||
let entry;
|
||||
|
@ -548,7 +575,7 @@ function handleUpdate(style, {reason, method} = {}) {
|
|||
handleUpdateInstalled(entry, reason);
|
||||
}
|
||||
filterAndAppend({entry}).then(sorter.update);
|
||||
if (!entry.matches('.hidden') && reason !== 'import') {
|
||||
if (!entry.matches('.hidden') && reason !== 'import' && reason !== 'sync') {
|
||||
animateElement(entry);
|
||||
requestAnimationFrame(() => scrollElementIntoView(entry));
|
||||
}
|
||||
|
@ -625,7 +652,7 @@ function switchUI({styleOnly} = {}) {
|
|||
filter: none;
|
||||
opacity: 1;
|
||||
}
|
||||
`) + (CHROME >= 3004 ? `
|
||||
`) + (CHROME >= 58 ? `
|
||||
.newUI .entry {
|
||||
contain: strict;
|
||||
}
|
||||
|
@ -677,15 +704,14 @@ function onVisibilityChange() {
|
|||
// page restored without reloading via history navigation (currently only in FF)
|
||||
// the catch here is that DOM may be outdated so we'll at least refresh the just edited style
|
||||
// assuming other changes aren't important enough to justify making a complicated DOM sync
|
||||
case 'visible':
|
||||
if (sessionStorage.justEditedStyleId) {
|
||||
API.getStyle(Number(sessionStorage.justEditedStyleId), true)
|
||||
.then(style => {
|
||||
handleUpdate(style, {method: 'styleUpdated'});
|
||||
});
|
||||
case 'visible': {
|
||||
const id = sessionStorage.justEditedStyleId;
|
||||
if (id) {
|
||||
handleUpdateForId(Number(id), {method: 'styleUpdated'});
|
||||
delete sessionStorage.justEditedStyleId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// going away
|
||||
case 'hidden':
|
||||
history.replaceState({scrollY: window.scrollY}, document.title);
|
||||
|
|
|
@ -32,7 +32,7 @@ const sorter = (() => {
|
|||
},
|
||||
dateUpdated: {
|
||||
text: t('dateUpdated'),
|
||||
parse: ({style}) => style.updateDate,
|
||||
parse: ({style}) => style.updateDate || style.installDate,
|
||||
sorter: sorterType.number
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"name": "Stylus",
|
||||
"version": "1.5.10",
|
||||
"version": "1.5.13",
|
||||
"minimum_chrome_version": "49",
|
||||
"description": "__MSG_description__",
|
||||
"homepage_url": "https://add0n.com/stylus.html",
|
||||
"manifest_version": 2,
|
||||
"icons": {
|
||||
"16": "/images/icon/16.png",
|
||||
"32": "/images/icon/32.png",
|
||||
"48": "/images/icon/48.png",
|
||||
"128": "/images/icon/128.png"
|
||||
"16": "images/icon/16.png",
|
||||
"32": "images/icon/32.png",
|
||||
"48": "images/icon/48.png",
|
||||
"128": "images/icon/128.png"
|
||||
},
|
||||
"permissions": [
|
||||
"tabs",
|
||||
|
@ -18,6 +18,7 @@
|
|||
"webRequestBlocking",
|
||||
"contextMenus",
|
||||
"storage",
|
||||
"unlimitedStorage",
|
||||
"alarms",
|
||||
"identity",
|
||||
"<all_urls>"
|
||||
|
@ -25,7 +26,6 @@
|
|||
"background": {
|
||||
"scripts": [
|
||||
"js/polyfill.js",
|
||||
"js/promisify.js",
|
||||
"js/messaging.js",
|
||||
"js/msg.js",
|
||||
"js/storage-util.js",
|
||||
|
@ -77,7 +77,6 @@
|
|||
"match_about_blank": true,
|
||||
"js": [
|
||||
"js/polyfill.js",
|
||||
"js/promisify.js",
|
||||
"js/msg.js",
|
||||
"js/prefs.js",
|
||||
"content/style-injector.js",
|
||||
|
@ -99,10 +98,10 @@
|
|||
],
|
||||
"browser_action": {
|
||||
"default_icon": {
|
||||
"16": "/images/icon/16w.png",
|
||||
"32": "/images/icon/32w.png",
|
||||
"19": "/images/icon/19w.png",
|
||||
"38": "/images/icon/38w.png"
|
||||
"16": "images/icon/16w.png",
|
||||
"32": "images/icon/32w.png",
|
||||
"19": "images/icon/19w.png",
|
||||
"38": "images/icon/38w.png"
|
||||
},
|
||||
"default_title": "Stylus",
|
||||
"default_popup": "popup.html"
|
||||
|
|
|
@ -134,6 +134,15 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.danger #message-box-buttons > button:not([data-focused-via-click]):first-child:focus {
|
||||
outline: red auto 1px;
|
||||
}
|
||||
|
||||
/* FF ignores color with 'auto' */
|
||||
.firefox .danger #message-box-buttons > button:not([data-focused-via-click]):first-child:focus {
|
||||
outline: red solid 1px;
|
||||
}
|
||||
|
||||
.non-windows #message-box-buttons {
|
||||
text-align: right;
|
||||
direction: rtl;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
<script src="js/polyfill.js"></script>
|
||||
<script src="js/dom.js"></script>
|
||||
<script src="js/promisify.js"></script>
|
||||
<script src="js/messaging.js"></script>
|
||||
<script src="js/msg.js"></script>
|
||||
<script src="js/localization.js"></script>
|
||||
|
|
|
@ -8,8 +8,8 @@ setupLivePrefs();
|
|||
enforceInputRange($('#popupWidth'));
|
||||
setTimeout(splitLongTooltips);
|
||||
|
||||
// TODO: add max version to re-enable once crbug.com/996859 is resolved
|
||||
if (!FIREFOX && CHROME >= 3809) {
|
||||
// https://github.com/openstyles/stylus/issues/822
|
||||
if (!FIREFOX && CHROME >= 76 && CHROME <= 81) {
|
||||
const dropboxOption = $('option[value="dropbox"]');
|
||||
dropboxOption.disabled = true;
|
||||
dropboxOption.setAttribute('title', t('hostDisabled'));
|
||||
|
@ -23,7 +23,7 @@ if (CHROME_HAS_BORDER_BUG) {
|
|||
}
|
||||
|
||||
// collapse #advanced block in Chrome pre-66 (classic chrome://extensions UI)
|
||||
if (!FIREFOX && !OPERA && CHROME < 3343) {
|
||||
if (!FIREFOX && !OPERA && CHROME < 66) {
|
||||
const block = $('#advanced');
|
||||
$('h1', block).onclick = event => {
|
||||
event.preventDefault();
|
||||
|
|
2789
package-lock.json
generated
2789
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
|
@ -1,30 +1,32 @@
|
|||
{
|
||||
"name": "Stylus",
|
||||
"version": "1.5.10",
|
||||
"version": "1.5.13",
|
||||
"description": "Redesign the web with Stylus, a user styles manager",
|
||||
"license": "GPL-3.0-only",
|
||||
"repository": "openstyles/stylus",
|
||||
"author": "Stylus Team",
|
||||
"devDependencies": {
|
||||
"archiver": "^3.1.1",
|
||||
"codemirror": "^5.51.0",
|
||||
"dependencies": {
|
||||
"codemirror": "^5.56.0",
|
||||
"db-to-cloud": "^0.4.5",
|
||||
"endent": "^1.4.0",
|
||||
"eslint": "^6.8.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"jsonlint": "^1.6.3",
|
||||
"less-bundle": "github:openstyles/less-bundle#v0.1.0",
|
||||
"lz-string-unsafe": "^1.4.4-fork-1",
|
||||
"make-fetch-happen": "^7.1.1",
|
||||
"semver-bundle": "^0.1.1",
|
||||
"shx": "^0.3.2",
|
||||
"stylelint-bundle": "^8.0.0",
|
||||
"stylus-lang-bundle": "^0.54.5",
|
||||
"usercss-meta": "^0.9.0",
|
||||
"uuid": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"archiver": "^4.0.1",
|
||||
"endent": "^1.4.0",
|
||||
"eslint": "^7.1.0",
|
||||
"fs-extra": "^9.0.0",
|
||||
"make-fetch-happen": "^8.0.7",
|
||||
"shx": "^0.3.2",
|
||||
"sync-version": "^1.0.1",
|
||||
"tiny-glob": "^0.2.6",
|
||||
"usercss-meta": "^0.9.0",
|
||||
"uuid": "^7.0.0-beta.0",
|
||||
"web-ext": "^4.1.0",
|
||||
"web-ext": "^4.2.0",
|
||||
"webext-tx-fix": "^0.3.3"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
@ -179,7 +179,6 @@
|
|||
<script src="manage/config-dialog.js"></script>
|
||||
|
||||
<script src="js/polyfill.js"></script>
|
||||
<script src="js/promisify.js"></script>
|
||||
<script src="js/dom.js"></script>
|
||||
<script src="js/messaging.js"></script>
|
||||
<script src="js/localization.js"></script>
|
||||
|
|
|
@ -341,6 +341,13 @@ a.configure[target="_blank"] .svg-icon.config {
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
#confirm button[data-cmd="ok"]:not([data-focused-via-click]):focus {
|
||||
outline: red auto 1px;
|
||||
}
|
||||
/* FF ignores color with 'auto' */
|
||||
.firefox #confirm button[data-cmd="ok"]:not([data-focused-via-click]):focus {
|
||||
outline: red solid 1px;
|
||||
}
|
||||
.menu-items-wrapper {
|
||||
width: 80%;
|
||||
max-height: 80%;
|
||||
|
|
|
@ -15,7 +15,7 @@ const ABOUT_BLANK = 'about:blank';
|
|||
const ENTRY_ID_PREFIX_RAW = 'style-';
|
||||
const ENTRY_ID_PREFIX = '#' + ENTRY_ID_PREFIX_RAW;
|
||||
|
||||
if (CHROME >= 3345 && CHROME < 3533) { // Chrome 66-69 adds a gap, https://crbug.com/821143
|
||||
if (CHROME >= 66 && CHROME <= 69) { // Chrome 66-69 adds a gap, https://crbug.com/821143
|
||||
document.head.appendChild($create('style', 'html { overflow: overlay }'));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* global tabURL handleEvent $ $$ prefs template FIREFOX chromeLocal debounce
|
||||
$create t API tWordBreak formatDate tryCatch tryJSONparse LZString
|
||||
ignoreChromeError download */
|
||||
promisifyChrome download */
|
||||
'use strict';
|
||||
|
||||
window.addEventListener('showStyles:done', function _() {
|
||||
|
@ -88,6 +88,9 @@ window.addEventListener('showStyles:done', function _() {
|
|||
return;
|
||||
|
||||
function init() {
|
||||
promisifyChrome({
|
||||
'storage.local': ['getBytesInUse'], // FF doesn't implement it
|
||||
});
|
||||
setTimeout(() => document.body.classList.add(BODY_CLASS));
|
||||
|
||||
$('#find-styles-inline-group').classList.add('hidden');
|
||||
|
@ -711,7 +714,7 @@ window.addEventListener('showStyles:done', function _() {
|
|||
return chromeLocal.loadLZStringScript().then(() =>
|
||||
tryJSONparse(LZString.decompressFromUTF16(item.payload)));
|
||||
} else if (item) {
|
||||
chrome.storage.local.remove(key);
|
||||
chromeLocal.remove(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -742,16 +745,8 @@ window.addEventListener('showStyles:done', function _() {
|
|||
|
||||
function cleanupCache() {
|
||||
chromeLocal.remove(CACHE_CLEANUP_NEEDED);
|
||||
if (chrome.storage.local.getBytesInUse) {
|
||||
chrome.storage.local.getBytesInUse(null, size => {
|
||||
if (size > CACHE_SIZE) {
|
||||
chrome.storage.local.get(null, cleanupCacheInternal);
|
||||
}
|
||||
ignoreChromeError();
|
||||
});
|
||||
} else {
|
||||
chrome.storage.local.get(null, cleanupCacheInternal);
|
||||
}
|
||||
Promise.resolve(!browser.storage.local.getBytesInUse ? 1e99 : browser.storage.local.getBytesInUse())
|
||||
.then(size => size > CACHE_SIZE && chromeLocal.get().then(cleanupCacheInternal));
|
||||
}
|
||||
|
||||
function cleanupCacheInternal(storage) {
|
||||
|
@ -764,9 +759,8 @@ window.addEventListener('showStyles:done', function _() {
|
|||
sortedByTime.slice(0, sortedByTime.length / 2);
|
||||
const toRemove = expired.length ? expired : sortedByTime;
|
||||
if (toRemove.length) {
|
||||
chrome.storage.local.remove(toRemove.map(item => item.key), ignoreChromeError);
|
||||
chromeLocal.remove(toRemove.map(item => item.key));
|
||||
}
|
||||
ignoreChromeError();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
@ -779,6 +773,7 @@ window.addEventListener('showStyles:done', function _() {
|
|||
return download(url, {
|
||||
body: null,
|
||||
responseType: 'json',
|
||||
timeout: 60e3,
|
||||
headers: {
|
||||
'Referrer-Policy': 'origin-when-cross-origin',
|
||||
[xhrSpoofTelltale]: requestId,
|
||||
|
|
|
@ -106,7 +106,7 @@ const colorConverter = (() => {
|
|||
if (!type) return;
|
||||
|
||||
const comma = value.includes(',') && !value.includes('/');
|
||||
const num = value.split(comma ? /\s*,\s*/ : /\s+(?!\/)|\s*\/\s*/);
|
||||
const num = value.trim().split(comma ? /\s*,\s*/ : /\s+(?!\/)|\s*\/\s*/);
|
||||
if (num.length < 3 || num.length > 4) return;
|
||||
if (num[3] && !validateAlpha(num[3])) return null;
|
||||
|
||||
|
|
|
@ -182,12 +182,13 @@
|
|||
|
||||
if (viewFrom > 0 || viewTo < cm.doc.size) {
|
||||
clearTimeout(state.colorizeTimer);
|
||||
state.colorizeTimer = setTimeout(colorizeInvisible, 100, state, viewFrom, viewTo, 0);
|
||||
state.line = 0;
|
||||
state.colorizeTimer = setTimeout(colorizeInvisible, 100, state, viewFrom, viewTo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function colorizeInvisible(state, viewFrom, viewTo, line) {
|
||||
function colorizeInvisible(state, viewFrom, viewTo) {
|
||||
const {cm} = state;
|
||||
const {curOp} = cm;
|
||||
if (!curOp) cm.startOperation();
|
||||
|
@ -197,22 +198,19 @@
|
|||
state.stopped = null;
|
||||
|
||||
// before the visible range
|
||||
if (viewFrom) {
|
||||
state.line = line;
|
||||
cm.doc.iter(line, viewFrom, lineHandle => colorizeLine(state, lineHandle));
|
||||
}
|
||||
cm.eachLine(state.line, viewFrom, lineHandle => colorizeLine(state, lineHandle));
|
||||
|
||||
// after the visible range
|
||||
if (!state.stopped && viewTo < cm.doc.size) {
|
||||
state.line = viewTo;
|
||||
cm.doc.iter(viewTo, cm.doc.size, lineHandle => colorizeLine(state, lineHandle));
|
||||
state.line = Math.max(viewTo, state.line);
|
||||
cm.eachLine(state.line, cm.doc.size, lineHandle => colorizeLine(state, lineHandle));
|
||||
}
|
||||
|
||||
updateMarkers(state);
|
||||
if (!curOp) cm.endOperation();
|
||||
|
||||
if (state.stopped) {
|
||||
state.colorizeTimer = setTimeout(colorizeInvisible, 0, state, viewFrom, viewFrom, state.line);
|
||||
state.colorizeTimer = setTimeout(colorizeInvisible, 0, state, viewFrom, viewTo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -229,30 +229,33 @@ var CSSLint = (() => {
|
|||
|
||||
// Example 1:
|
||||
|
||||
/* csslint ignore:start */
|
||||
// the chunk of code where errors won't be reported
|
||||
// the chunk's start is hardwired to the line of the opening comment
|
||||
// the chunk's end is hardwired to the line of the closing comment
|
||||
/* csslint ignore:end */
|
||||
/* csslint ignore:start */
|
||||
/*
|
||||
the chunk of code where errors won't be reported
|
||||
the chunk's start is hardwired to the line of the opening comment
|
||||
the chunk's end is hardwired to the line of the closing comment
|
||||
*/
|
||||
/* csslint ignore:end */
|
||||
|
||||
// Example 2:
|
||||
// allow rule violations on the current line:
|
||||
|
||||
/* csslint allow:rulename1,rulename2,... */
|
||||
// allows to break the specified rules on the next single line of code
|
||||
// foo: bar; /* csslint allow:rulename1,rulename2,... */
|
||||
/* csslint allow:rulename1,rulename2,... */ // foo: bar;
|
||||
|
||||
// Example 3:
|
||||
|
||||
/* csslint rulename1 */
|
||||
/* csslint rulename2:N */
|
||||
/* csslint rulename3:N, rulename4:N */
|
||||
/* csslint rulename1 */
|
||||
/* csslint rulename2:N */
|
||||
/* csslint rulename3:N, rulename4:N */
|
||||
|
||||
// entire code is affected;
|
||||
// comments futher down the code extend/override previous comments of this kind
|
||||
// values for N:
|
||||
// "2" or "true" means "error"
|
||||
// "1" or nothing means "warning" - note in this case ":" can also be omitted
|
||||
// "0" or "false" means "ignore"
|
||||
// (the quotes are added here for convenience, don't put them in the actual comments)
|
||||
/* entire code is affected;
|
||||
* comments futher down the code extend/override previous comments of this kind
|
||||
* values for N (without the backquotes):
|
||||
`2` or `true` means "error"
|
||||
`1` or omitted means "warning" (when omitting, the colon can be omitted too)
|
||||
`0` or `false` means "ignore"
|
||||
*/
|
||||
|
||||
function applyEmbeddedOverrides(text, ruleset, allow, ignore) {
|
||||
let ignoreStart = null;
|
||||
|
@ -282,7 +285,7 @@ var CSSLint = (() => {
|
|||
allowRuleset[allowRule.trim()] = true;
|
||||
num++;
|
||||
});
|
||||
if (num) allow[lineno + 1] = allowRuleset;
|
||||
if (num) allow[lineno] = allowRuleset;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -319,7 +319,7 @@ self.parserlib = (() => {
|
|||
'drop-initial-before-align': 'caps-height | baseline | use-script | before-edge | text-before-edge | ' +
|
||||
'after-edge | text-after-edge | central | middle | ideographic | alphabetic | ' +
|
||||
'hanging | mathematical',
|
||||
'drop-initial-size': 'auto | line | <length> | <percentage>',
|
||||
'drop-initial-size': 'auto | line | <length-percentage>',
|
||||
'drop-initial-value': '<integer>',
|
||||
|
||||
// E
|
||||
|
@ -347,19 +347,28 @@ self.parserlib = (() => {
|
|||
'flood-opacity': '<opacity-value>',
|
||||
'font': '<font-shorthand> | caption | icon | menu | message-box | small-caption | status-bar',
|
||||
'font-family': '<font-family>',
|
||||
'font-feature-settings': '<feature-tag-value> | normal',
|
||||
'font-feature-settings': '<feature-tag-value># | normal',
|
||||
'font-kerning': 'auto | normal | none',
|
||||
'font-language-override': 'normal | <string>',
|
||||
'font-optical-sizing': 'auto | none',
|
||||
'font-palette': 'none | normal | light | dark | <ident>',
|
||||
'font-size': '<font-size>',
|
||||
'font-size-adjust': '<number> | none',
|
||||
'font-stretch': '<font-stretch>',
|
||||
'font-style': '<font-style>',
|
||||
'font-synthesis': 'none | [ weight || style ]',
|
||||
'font-synthesis-style': 'auto | none',
|
||||
'font-synthesis-weight': 'auto | none',
|
||||
'font-synthesis-small-caps': 'auto | none',
|
||||
'font-variant': '<font-variant> | normal | none',
|
||||
'font-variant-alternates': '<font-variant-alternates> | normal',
|
||||
'font-variant-caps': '<font-variant-caps> | normal',
|
||||
'font-variant-east-asian': '<font-variant-east-asian> | normal',
|
||||
'font-variant-emoji': 'auto | text | emoji | unicode',
|
||||
'font-variant-ligatures': '<font-variant-ligatures> | normal | none',
|
||||
'font-variant-numeric': '<font-variant-numeric> | normal',
|
||||
'font-variant-position': 'normal | sub | super',
|
||||
'font-variation-settings': 'normal | [ <string> <number>]#',
|
||||
'font-weight': '<font-weight>',
|
||||
'-ms-flex-align': 'start | end | center | stretch | baseline',
|
||||
'-ms-flex-order': '<number>',
|
||||
|
@ -392,7 +401,7 @@ self.parserlib = (() => {
|
|||
'grid-gap': '<row-gap> <column-gap>?',
|
||||
|
||||
// H
|
||||
'hanging-punctuation': 1,
|
||||
'hanging-punctuation': 'none | [ first || [ force-end | allow-end ] || last ]',
|
||||
'height': 'auto | <width-height>',
|
||||
'hyphenate-after': '<integer> | auto',
|
||||
'hyphenate-before': '<integer> | auto',
|
||||
|
@ -431,7 +440,7 @@ self.parserlib = (() => {
|
|||
'left': '<width>',
|
||||
'letter-spacing': '<length> | normal',
|
||||
'line-height': '<line-height>',
|
||||
'line-break': 'auto | loose | normal | strict',
|
||||
'line-break': 'auto | loose | normal | strict | anywhere',
|
||||
'line-stacking': 1,
|
||||
'line-stacking-ruby': 'exclude-ruby | include-ruby',
|
||||
'line-stacking-shift': 'consider-shifts | disregard-shifts',
|
||||
|
@ -502,9 +511,14 @@ self.parserlib = (() => {
|
|||
'overflow-block': '<overflow>',
|
||||
'overflow-inline': '<overflow>',
|
||||
'overflow-style': 1,
|
||||
'overflow-wrap': 'normal | break-word',
|
||||
'overflow-wrap': 'normal | break-word | anywhere',
|
||||
'overflow-x': '<overflow>',
|
||||
'overflow-y': '<overflow>',
|
||||
'overscroll-behavior': '<overscroll>{1,2}',
|
||||
'overscroll-behavior-block': '<overscroll>',
|
||||
'overscroll-behavior-inline': '<overscroll>',
|
||||
'overscroll-behavior-x': '<overscroll>',
|
||||
'overscroll-behavior-y': '<overscroll>',
|
||||
|
||||
// P
|
||||
'padding': '<padding-width>{1,4}',
|
||||
|
@ -564,6 +578,8 @@ self.parserlib = (() => {
|
|||
|
||||
// S
|
||||
'scale': 'none | <number>{1,3}',
|
||||
'scrollbar-color': 'auto | dark | light | <color>{2}',
|
||||
'scrollbar-width': 'auto | thin | none',
|
||||
'shape-inside': 'auto | outside-shape | [ <basic-shape> || shape-box ] | <image> | display',
|
||||
'shape-rendering': 'auto | optimizeSpeed | crispEdges | geometricPrecision',
|
||||
'size': 1,
|
||||
|
@ -588,14 +604,14 @@ self.parserlib = (() => {
|
|||
|
||||
// T
|
||||
'table-layout': 'auto | fixed',
|
||||
'tab-size': '<integer> | <length>',
|
||||
'tab-size': '<number> | <length>',
|
||||
'target': 1,
|
||||
'target-name': 1,
|
||||
'target-new': 1,
|
||||
'target-position': 1,
|
||||
'text-align': 'start | end | left | right | center | justify | match-parent | justify-all',
|
||||
'text-align-all': 'start | end | left | right | center | justify | match-parent',
|
||||
'text-align-last': 'auto | start | end | left | right | center | justify',
|
||||
'text-align': '<text-align> | justify-all',
|
||||
'text-align-all': '<text-align>',
|
||||
'text-align-last': '<text-align> | auto',
|
||||
'text-anchor': 'start | middle | end',
|
||||
'text-decoration': '<text-decoration-line> || <text-decoration-style> || <color>',
|
||||
'text-decoration-color': '<color>',
|
||||
|
@ -607,13 +623,13 @@ self.parserlib = (() => {
|
|||
'text-emphasis-style': '<text-emphasis-style>',
|
||||
'text-emphasis-position': '[ over | under ] && [ right | left ]?',
|
||||
'text-height': 1,
|
||||
'text-indent': '<length> | <percentage>',
|
||||
'text-justify': 'auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida',
|
||||
'text-indent': '<length-percentage> && hanging? && each-line?',
|
||||
'text-justify': 'auto | none | inter-word | inter-character',
|
||||
'text-outline': 1,
|
||||
'text-overflow': 'clip | ellipsis',
|
||||
'text-rendering': 'auto | optimizeSpeed | optimizeLegibility | geometricPrecision',
|
||||
'text-shadow': 'none | [ <color>? && <length>{2,3} ]#',
|
||||
'text-transform': 'capitalize | uppercase | lowercase | none',
|
||||
'text-transform': 'none | [ capitalize | uppercase | lowercase ] || full-width || full-size-kana',
|
||||
'text-underline-position': 'auto | [ under || [ left | right ] ]',
|
||||
'text-wrap': 'normal | none | avoid',
|
||||
'top': '<width>',
|
||||
|
@ -650,15 +666,14 @@ self.parserlib = (() => {
|
|||
'volume': 1,
|
||||
|
||||
// W
|
||||
'white-space': 'normal | pre | nowrap | pre-wrap | pre-line | -pre-wrap |' +
|
||||
' -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap',
|
||||
'white-space': 'normal | pre | nowrap | pre-wrap | break-spaces | pre-line',
|
||||
'white-space-collapse': 1,
|
||||
'widows': '<integer>',
|
||||
'width': 'auto | <width-height>',
|
||||
'will-change': '<will-change>',
|
||||
'word-break': 'normal | keep-all | break-all',
|
||||
'word-break': 'normal | keep-all | break-all | break-word',
|
||||
'word-spacing': '<length> | normal',
|
||||
'word-wrap': 'normal | break-word',
|
||||
'word-wrap': 'normal | break-word | anywhere',
|
||||
'writing-mode': 'horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | ' +
|
||||
'bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb',
|
||||
|
||||
|
@ -711,7 +726,7 @@ self.parserlib = (() => {
|
|||
|
||||
'<clip-source>': '<uri>',
|
||||
|
||||
'<column-gap>': 'normal | <length> | <percentage>',
|
||||
'<column-gap>': 'normal | <length-percentage>',
|
||||
|
||||
'<content-distribution>': 'space-between | space-around | space-evenly | stretch',
|
||||
'<content-position>': 'center | start | end | flex-start | flex-end',
|
||||
|
@ -747,17 +762,17 @@ self.parserlib = (() => {
|
|||
'<flex-shrink>': '<number>',
|
||||
'<flex-wrap>': 'nowrap | wrap | wrap-reverse',
|
||||
|
||||
'<font-size>': '<absolute-size> | <relative-size> | <length> | <percentage>',
|
||||
'<font-stretch>': 'normal | ultra-condensed | extra-condensed | condensed | semi-condensed | ' +
|
||||
'<font-size>': '<absolute-size> | <relative-size> | <length-percentage>',
|
||||
'<font-stretch>': 'normal | <percentage> | ultra-condensed | extra-condensed | condensed | semi-condensed | ' +
|
||||
'semi-expanded | expanded | extra-expanded | ultra-expanded',
|
||||
'<font-style>': 'normal | italic | oblique',
|
||||
'<font-style>': 'normal | italic | oblique <angle>?',
|
||||
'<font-variant-caps>': 'small-caps | all-small-caps | petite-caps | all-petite-caps | ' +
|
||||
'unicase | titling-caps',
|
||||
'<font-variant-css21>': 'normal | small-caps',
|
||||
'<font-weight>': 'normal | bold | bolder | lighter | ' +
|
||||
'100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900',
|
||||
'<font-weight>': 'normal | bold | bolder | lighter | <number>',
|
||||
|
||||
'<generic-family>': 'serif | sans-serif | cursive | fantasy | monospace',
|
||||
'<generic-family>': 'serif | sans-serif | cursive | fantasy | monospace | system-ui | emoji | ' +
|
||||
'math | fangsong | ui-serif | ui-sans-serif | ui-monospace | ui-rounded',
|
||||
|
||||
'<geometry-box>': '<shape-box> | fill-box | stroke-box | view-box',
|
||||
|
||||
|
@ -798,7 +813,7 @@ self.parserlib = (() => {
|
|||
|
||||
'<line>': part => part.type === 'integer',
|
||||
|
||||
'<line-height>': '<number> | <length> | <percentage> | normal',
|
||||
'<line-height>': '<number> | <length-percentage> | normal',
|
||||
|
||||
'<line-names>': function (part) {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
|
@ -868,6 +883,8 @@ self.parserlib = (() => {
|
|||
|
||||
'<string>': part => part.type === 'string',
|
||||
|
||||
'<text-align>': 'start | end | left | right | center | justify | match-parent',
|
||||
|
||||
'<text-decoration-style>': 'solid | double | dotted | dashed | wavy',
|
||||
|
||||
'<time>': part => part.type === 'time',
|
||||
|
@ -901,7 +918,7 @@ self.parserlib = (() => {
|
|||
);
|
||||
},
|
||||
|
||||
'<width>': '<length> | <percentage> | auto',
|
||||
'<width>': '<length-percentage> | auto',
|
||||
},
|
||||
|
||||
complex: {
|
||||
|
@ -929,7 +946,7 @@ self.parserlib = (() => {
|
|||
'[ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ] | ' +
|
||||
'[ left | center | right | top | bottom | <length-percentage> ]',
|
||||
|
||||
'<bg-size>': '[ <length> | <percentage> | auto ]{1,2} | cover | contain',
|
||||
'<bg-size>': '[ <length-percentage> | auto ]{1,2} | cover | contain',
|
||||
|
||||
'<border-image-outset>': '[ <length> | <number> ]{1,4}',
|
||||
'<border-image-repeat>': '[ stretch | repeat | round | space ]{1,2}',
|
||||
|
@ -943,7 +960,7 @@ self.parserlib = (() => {
|
|||
Matcher.cast('<nonnegative-number-or-percentage>'),
|
||||
Matcher.cast('<nonnegative-number-or-percentage>'),
|
||||
'fill'),
|
||||
'<border-image-width>': '[ <length> | <percentage> | <number> | auto ]{1,4}',
|
||||
'<border-image-width>': '[ <length-percentage> | <number> | auto ]{1,4}',
|
||||
'<border-radius>': '<nonnegative-length-or-percentage>{1,4} [ / <nonnegative-length-or-percentage>{1,4} ]?',
|
||||
'<border-shorthand>': '<border-width> || <border-style> || <color>',
|
||||
|
||||
|
@ -1050,6 +1067,8 @@ self.parserlib = (() => {
|
|||
'<hsl-color>': '[ <number> | <angle> ] <percentage>{2} [ / <nonnegative-number-or-percentage> ]? | ' +
|
||||
'[ <number> | <angle> ] , <percentage>#{2} [ , <nonnegative-number-or-percentage> ]?',
|
||||
|
||||
'<overscroll>': 'contain | none | auto',
|
||||
|
||||
'<shadow>': 'inset? && [ <length>{2,4} && <color>? ]',
|
||||
|
||||
'<single-timing-function>': 'linear | <cubic-bezier-timing-function> | <step-timing-function> | frames()',
|
||||
|
@ -1076,7 +1095,7 @@ self.parserlib = (() => {
|
|||
|
||||
'<will-change>': 'auto | <animateable-feature>#',
|
||||
|
||||
'<x-one-radius>': '[ <length> | <percentage> ]{1,2}',
|
||||
'<x-one-radius>': '<length-percentage>{1,2}',
|
||||
},
|
||||
|
||||
functions: {
|
||||
|
@ -1345,165 +1364,154 @@ self.parserlib = (() => {
|
|||
* The following token names are defined in CSS3 Grammar:
|
||||
* https://www.w3.org/TR/css3-syntax/#lexical
|
||||
*/
|
||||
const Tokens = [
|
||||
const Tokens = Object.assign([], {
|
||||
EOF: {}, // must be the first token
|
||||
}, {
|
||||
// HTML-style comments
|
||||
{name: 'CDO'},
|
||||
{name: 'CDC'},
|
||||
CDO: {},
|
||||
CDC: {},
|
||||
|
||||
// ignorables
|
||||
{name: 'S', whitespace: true},
|
||||
{name: 'COMMENT', whitespace: true, comment: true, hide: true},
|
||||
S: {whitespace: true},
|
||||
COMMENT: {whitespace: true, comment: true, hide: true},
|
||||
|
||||
// attribute equality
|
||||
{name: 'INCLUDES', text: '~='},
|
||||
{name: 'DASHMATCH', text: '|='},
|
||||
{name: 'PREFIXMATCH', text: '^='},
|
||||
{name: 'SUFFIXMATCH', text: '$='},
|
||||
{name: 'SUBSTRINGMATCH', text: '*='},
|
||||
INCLUDES: {text: '~='},
|
||||
DASHMATCH: {text: '|='},
|
||||
PREFIXMATCH: {text: '^='},
|
||||
SUFFIXMATCH: {text: '$='},
|
||||
SUBSTRINGMATCH: {text: '*='},
|
||||
|
||||
// identifier types
|
||||
{name: 'STRING'},
|
||||
{name: 'IDENT'},
|
||||
{name: 'HASH'},
|
||||
STRING: {},
|
||||
IDENT: {},
|
||||
HASH: {},
|
||||
|
||||
// at-keywords
|
||||
{name: 'IMPORT_SYM', text: '@import'},
|
||||
{name: 'PAGE_SYM', text: '@page'},
|
||||
{name: 'MEDIA_SYM', text: '@media'},
|
||||
{name: 'FONT_FACE_SYM', text: '@font-face'},
|
||||
{name: 'CHARSET_SYM', text: '@charset'},
|
||||
{name: 'NAMESPACE_SYM', text: '@namespace'},
|
||||
{name: 'SUPPORTS_SYM', text: '@supports'},
|
||||
{name: 'VIEWPORT_SYM', text: ['@viewport', '@-ms-viewport', '@-o-viewport']},
|
||||
{name: 'DOCUMENT_SYM', text: ['@document', '@-moz-document']},
|
||||
{name: 'UNKNOWN_SYM'}, //{ name: "ATKEYWORD"},
|
||||
IMPORT_SYM: {text: '@import'},
|
||||
PAGE_SYM: {text: '@page'},
|
||||
MEDIA_SYM: {text: '@media'},
|
||||
FONT_FACE_SYM: {text: '@font-face'},
|
||||
CHARSET_SYM: {text: '@charset'},
|
||||
NAMESPACE_SYM: {text: '@namespace'},
|
||||
SUPPORTS_SYM: {text: '@supports'},
|
||||
VIEWPORT_SYM: {text: ['@viewport', '@-ms-viewport', '@-o-viewport']},
|
||||
DOCUMENT_SYM: {text: ['@document', '@-moz-document']},
|
||||
UNKNOWN_SYM: {}, //{ name: "ATKEYWORD"},
|
||||
|
||||
// CSS3 animations
|
||||
{name: 'KEYFRAMES_SYM', text: ['@keyframes', '@-webkit-keyframes', '@-moz-keyframes', '@-o-keyframes']},
|
||||
KEYFRAMES_SYM: {text: ['@keyframes', '@-webkit-keyframes', '@-moz-keyframes', '@-o-keyframes']},
|
||||
|
||||
// important symbol
|
||||
{name: 'IMPORTANT_SYM'},
|
||||
IMPORTANT_SYM: {},
|
||||
|
||||
// measurements
|
||||
{name: 'LENGTH'},
|
||||
{name: 'ANGLE'},
|
||||
{name: 'TIME'},
|
||||
{name: 'FREQ'},
|
||||
{name: 'DIMENSION'},
|
||||
{name: 'PERCENTAGE'},
|
||||
{name: 'NUMBER'},
|
||||
LENGTH: {},
|
||||
ANGLE: {},
|
||||
TIME: {},
|
||||
FREQ: {},
|
||||
DIMENSION: {},
|
||||
PERCENTAGE: {},
|
||||
NUMBER: {},
|
||||
|
||||
// functions
|
||||
{name: 'URI'},
|
||||
{name: 'FUNCTION'},
|
||||
URI: {},
|
||||
FUNCTION: {},
|
||||
|
||||
// Unicode ranges
|
||||
{name: 'UNICODE_RANGE'},
|
||||
UNICODE_RANGE: {},
|
||||
|
||||
/*
|
||||
* The following token names are defined in CSS3 Selectors: https://www.w3.org/TR/css3-selectors/#selector-syntax
|
||||
*/
|
||||
|
||||
// invalid string
|
||||
{name: 'INVALID'},
|
||||
INVALID: {},
|
||||
|
||||
// combinators
|
||||
{name: 'PLUS', text: '+'},
|
||||
{name: 'GREATER', text: '>'},
|
||||
{name: 'COMMA', text: ','},
|
||||
{name: 'TILDE', text: '~'},
|
||||
PLUS: {text: '+'},
|
||||
GREATER: {text: '>'},
|
||||
COMMA: {text: ','},
|
||||
TILDE: {text: '~'},
|
||||
COLUMN: {text: '||'},
|
||||
|
||||
// modifier
|
||||
{name: 'NOT'},
|
||||
{name: 'ANY', text: ['any', '-webkit-any', '-moz-any']},
|
||||
{name: 'MATCHES'},
|
||||
{name: 'IS'},
|
||||
NOT: {},
|
||||
ANY: {text: ['any', '-webkit-any', '-moz-any']},
|
||||
IS: {},
|
||||
WHERE: {},
|
||||
|
||||
/*
|
||||
* Defined in CSS3 Paged Media
|
||||
*/
|
||||
{name: 'TOPLEFTCORNER_SYM', text: '@top-left-corner'},
|
||||
{name: 'TOPLEFT_SYM', text: '@top-left'},
|
||||
{name: 'TOPCENTER_SYM', text: '@top-center'},
|
||||
{name: 'TOPRIGHT_SYM', text: '@top-right'},
|
||||
{name: 'TOPRIGHTCORNER_SYM', text: '@top-right-corner'},
|
||||
{name: 'BOTTOMLEFTCORNER_SYM', text: '@bottom-left-corner'},
|
||||
{name: 'BOTTOMLEFT_SYM', text: '@bottom-left'},
|
||||
{name: 'BOTTOMCENTER_SYM', text: '@bottom-center'},
|
||||
{name: 'BOTTOMRIGHT_SYM', text: '@bottom-right'},
|
||||
{name: 'BOTTOMRIGHTCORNER_SYM', text: '@bottom-right-corner'},
|
||||
{name: 'LEFTTOP_SYM', text: '@left-top'},
|
||||
{name: 'LEFTMIDDLE_SYM', text: '@left-middle'},
|
||||
{name: 'LEFTBOTTOM_SYM', text: '@left-bottom'},
|
||||
{name: 'RIGHTTOP_SYM', text: '@right-top'},
|
||||
{name: 'RIGHTMIDDLE_SYM', text: '@right-middle'},
|
||||
{name: 'RIGHTBOTTOM_SYM', text: '@right-bottom'},
|
||||
TOPLEFTCORNER_SYM: {text: '@top-left-corner'},
|
||||
TOPLEFT_SYM: {text: '@top-left'},
|
||||
TOPCENTER_SYM: {text: '@top-center'},
|
||||
TOPRIGHT_SYM: {text: '@top-right'},
|
||||
TOPRIGHTCORNER_SYM: {text: '@top-right-corner'},
|
||||
BOTTOMLEFTCORNER_SYM: {text: '@bottom-left-corner'},
|
||||
BOTTOMLEFT_SYM: {text: '@bottom-left'},
|
||||
BOTTOMCENTER_SYM: {text: '@bottom-center'},
|
||||
BOTTOMRIGHT_SYM: {text: '@bottom-right'},
|
||||
BOTTOMRIGHTCORNER_SYM: {text: '@bottom-right-corner'},
|
||||
LEFTTOP_SYM: {text: '@left-top'},
|
||||
LEFTMIDDLE_SYM: {text: '@left-middle'},
|
||||
LEFTBOTTOM_SYM: {text: '@left-bottom'},
|
||||
RIGHTTOP_SYM: {text: '@right-top'},
|
||||
RIGHTMIDDLE_SYM: {text: '@right-middle'},
|
||||
RIGHTBOTTOM_SYM: {text: '@right-bottom'},
|
||||
|
||||
/*
|
||||
* The following token names are defined in CSS3 Media Queries: https://www.w3.org/TR/css3-mediaqueries/#syntax
|
||||
*/
|
||||
{name: 'RESOLUTION', state: 'media'},
|
||||
RESOLUTION: {state: 'media'},
|
||||
|
||||
/*
|
||||
* The following token names are not defined in any CSS specification but are used by the lexer.
|
||||
*/
|
||||
|
||||
// not a real token, but useful for stupid IE filters
|
||||
{name: 'IE_FUNCTION'},
|
||||
IE_FUNCTION: {},
|
||||
|
||||
// part of CSS3 grammar but not the Flex code
|
||||
{name: 'CHAR'},
|
||||
CHAR: {},
|
||||
|
||||
// TODO: Needed?
|
||||
// Not defined as tokens, but might as well be
|
||||
{name: 'PIPE', text: '|'},
|
||||
{name: 'SLASH', text: '/'},
|
||||
{name: 'MINUS', text: '-'},
|
||||
{name: 'STAR', text: '*'},
|
||||
PIPE: {text: '|'},
|
||||
SLASH: {text: '/'},
|
||||
MINUS: {text: '-'},
|
||||
STAR: {text: '*'},
|
||||
|
||||
{name: 'LBRACE', text: '{', endChar: '}'},
|
||||
{name: 'RBRACE', text: '}'},
|
||||
{name: 'LBRACKET', text: '[', endChar: ']'},
|
||||
{name: 'RBRACKET', text: ']'},
|
||||
{name: 'EQUALS', text: '='},
|
||||
{name: 'COLON', text: ':'},
|
||||
{name: 'SEMICOLON', text: ';'},
|
||||
{name: 'LPAREN', text: '(', endChar: ')'},
|
||||
{name: 'RPAREN', text: ')'},
|
||||
{name: 'DOT', text: '.'},
|
||||
LBRACE: {text: '{', endChar: '}'},
|
||||
RBRACE: {text: '}'},
|
||||
LBRACKET: {text: '[', endChar: ']'},
|
||||
RBRACKET: {text: ']'},
|
||||
EQUALS: {text: '='},
|
||||
COLON: {text: ':'},
|
||||
SEMICOLON: {text: ';'},
|
||||
LPAREN: {text: '(', endChar: ')'},
|
||||
RPAREN: {text: ')'},
|
||||
DOT: {text: '.'},
|
||||
|
||||
{name: 'USO_VAR', comment: true},
|
||||
{name: 'CUSTOM_PROP'},
|
||||
];
|
||||
|
||||
{
|
||||
Tokens.UNKNOWN = -1;
|
||||
Tokens.unshift({name: 'EOF'});
|
||||
|
||||
const nameMap = [];
|
||||
const typeMap = new Map();
|
||||
for (let i = 0, len = Tokens.length; i < len; i++) {
|
||||
nameMap.push(Tokens[i].name);
|
||||
Tokens[Tokens[i].name] = i;
|
||||
if (Tokens[i].text) {
|
||||
if (Tokens[i].text instanceof Array) {
|
||||
for (let j = 0; j < Tokens[i].text.length; j++) {
|
||||
typeMap.set(Tokens[i].text[j], i);
|
||||
}
|
||||
} else {
|
||||
typeMap.set(Tokens[i].text, i);
|
||||
}
|
||||
USO_VAR: {comment: true},
|
||||
CUSTOM_PROP: {},
|
||||
});
|
||||
// make Tokens an array of tokens, store the index in original prop, add 'name' to each token
|
||||
const typeMap = new Map();
|
||||
for (const [k, val] of Object.entries(Tokens)) {
|
||||
const index = Tokens[k] = Tokens.length;
|
||||
val.name = k;
|
||||
Tokens.push(val);
|
||||
const {text} = val;
|
||||
if (text) {
|
||||
for (const item of Array.isArray(text) ? text : [text]) {
|
||||
typeMap.set(item, index);
|
||||
}
|
||||
}
|
||||
|
||||
Tokens.name = function (tt) {
|
||||
return nameMap[tt];
|
||||
};
|
||||
|
||||
Tokens.type = function (c) {
|
||||
return typeMap.get(c) || -1;
|
||||
};
|
||||
}
|
||||
Tokens.UNKNOWN = -1;
|
||||
Tokens.name = index => (Tokens[index] || {}).name;
|
||||
Tokens.type = text => typeMap.get(text) || -1;
|
||||
|
||||
//endregion
|
||||
//region lowerCase helper
|
||||
|
@ -2204,6 +2212,7 @@ self.parserlib = (() => {
|
|||
value === '>' ? 'child' :
|
||||
value === '+' ? 'adjacent-sibling' :
|
||||
value === '~' ? 'sibling' :
|
||||
value === '||' ? 'column' :
|
||||
!value.trim() ? 'descendant' :
|
||||
'unknown';
|
||||
}
|
||||
|
@ -2603,9 +2612,11 @@ self.parserlib = (() => {
|
|||
if (expression._i < expression._parts.length - 1) {
|
||||
expression.mark();
|
||||
expression._i++;
|
||||
result = ValidationTypes.isType(expression, type);
|
||||
expression.restore();
|
||||
expression._i += result ? 1 : 0;
|
||||
if (ValidationTypes.isType(expression, type)) {
|
||||
expression.drop();
|
||||
} else {
|
||||
expression.restore();
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
|
||||
|
@ -2940,6 +2951,7 @@ self.parserlib = (() => {
|
|||
* - PREFIXMATCH
|
||||
* - SUFFIXMATCH
|
||||
* - SUBSTRINGMATCH
|
||||
* - COLUMN
|
||||
* - CHAR
|
||||
*/
|
||||
case '|':
|
||||
|
@ -2947,10 +2959,13 @@ self.parserlib = (() => {
|
|||
case '^':
|
||||
case '$':
|
||||
case '*':
|
||||
return reader.peek() === '=' ?
|
||||
this.comparisonToken(c, pos) :
|
||||
this.charToken(c, pos);
|
||||
|
||||
return (
|
||||
reader.peek() === '=' ?
|
||||
this.comparisonToken(c, pos) :
|
||||
c === '|' && reader.readMatch('|') ?
|
||||
this.createToken(Tokens.COLUMN, '||', pos) :
|
||||
this.charToken(c, pos)
|
||||
);
|
||||
/*
|
||||
* Potential tokens:
|
||||
* - STRING
|
||||
|
@ -3040,8 +3055,8 @@ self.parserlib = (() => {
|
|||
* Potential tokens:
|
||||
* - ANY
|
||||
* - IS
|
||||
* - MATCHES
|
||||
* - NOT
|
||||
* - WHERE
|
||||
* - CHAR
|
||||
*/
|
||||
case ':':
|
||||
|
@ -3255,18 +3270,18 @@ self.parserlib = (() => {
|
|||
// NOT
|
||||
// IS
|
||||
// ANY
|
||||
// MATCHES
|
||||
// CHAR
|
||||
notOrIsToken(first, pos) {
|
||||
// first is always ':'
|
||||
const reader = this._reader;
|
||||
const func = reader.readMatch(/(not|is|(-(moz|webkit)-)?(any|matches))\(/iy);
|
||||
const func = reader.readMatch(/(not|is|where|(-(moz|webkit)-)?any)\(/iy);
|
||||
if (func) {
|
||||
const lcase = func[0].toLowerCase();
|
||||
const type =
|
||||
lcase === 'n' ? Tokens.NOT :
|
||||
lcase === 'i' ? Tokens.IS :
|
||||
lcase === 'm' ? Tokens.MATCHES : Tokens.ANY;
|
||||
lcase === 'w' ? Tokens.WHERE :
|
||||
Tokens.ANY;
|
||||
return this.createToken(type, first + func, pos);
|
||||
}
|
||||
return this.charToken(first, pos);
|
||||
|
@ -4017,7 +4032,7 @@ self.parserlib = (() => {
|
|||
const stream = this._tokenStream;
|
||||
if (stream.match(Tokens.LPAREN)) {
|
||||
this._ws();
|
||||
if (stream.match(Tokens.IDENT)) {
|
||||
if (stream.match([Tokens.IDENT, Tokens.CUSTOM_PROP])) {
|
||||
// look ahead for not keyword,
|
||||
// if not given, continue with declaration condition.
|
||||
const ident = lower(stream._token.value);
|
||||
|
@ -4366,7 +4381,7 @@ self.parserlib = (() => {
|
|||
}
|
||||
|
||||
_combinator() {
|
||||
if (this._tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])) {
|
||||
if (this._tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE, Tokens.COLUMN])) {
|
||||
const value = new Combinator(this._tokenStream._token);
|
||||
this._ws();
|
||||
return value;
|
||||
|
@ -4630,7 +4645,8 @@ self.parserlib = (() => {
|
|||
this._ws();
|
||||
|
||||
if (stream.match([Tokens.IDENT])) {
|
||||
if (lower(stream._token.value) === 'i') {
|
||||
const caseMod = lower(stream._token.value);
|
||||
if (caseMod === 'i' || caseMod === 's') {
|
||||
value += stream._token.value +
|
||||
this._ws();
|
||||
} else {
|
||||
|
@ -4710,7 +4726,7 @@ self.parserlib = (() => {
|
|||
|
||||
_is() {
|
||||
const stream = this._tokenStream;
|
||||
if (!stream.match([Tokens.IS, Tokens.ANY, Tokens.MATCHES])) return null;
|
||||
if (!stream.match([Tokens.IS, Tokens.ANY, Tokens.WHERE])) return null;
|
||||
|
||||
let arg;
|
||||
const start = stream._token;
|
||||
|
@ -5421,6 +5437,7 @@ self.parserlib = (() => {
|
|||
]),
|
||||
|
||||
supports: new Map([
|
||||
[Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes],
|
||||
[Tokens.MEDIA_SYM, Parser.prototype._media],
|
||||
[Tokens.SUPPORTS_SYM, Parser.prototype._supports],
|
||||
[Tokens.DOCUMENT_SYM, Parser.prototype._documentMisplaced],
|
||||
|
@ -5428,6 +5445,7 @@ self.parserlib = (() => {
|
|||
]),
|
||||
|
||||
media: new Map([
|
||||
[Tokens.KEYFRAMES_SYM, Parser.prototype._keyframes],
|
||||
[Tokens.MEDIA_SYM, Parser.prototype._media],
|
||||
[Tokens.DOCUMENT_SYM, Parser.prototype._documentMisplaced],
|
||||
[Tokens.SUPPORTS_SYM, Parser.prototype._supports],
|
||||
|
@ -5443,7 +5461,7 @@ self.parserlib = (() => {
|
|||
[Tokens.COLON, Parser.prototype._pseudo],
|
||||
[Tokens.IS, Parser.prototype._is],
|
||||
[Tokens.ANY, Parser.prototype._is],
|
||||
[Tokens.MATCHES, Parser.prototype._is],
|
||||
[Tokens.WHERE, Parser.prototype._is],
|
||||
[Tokens.NOT, Parser.prototype._negation],
|
||||
]),
|
||||
};
|
||||
|
|
2
vendor/codemirror/README.md
vendored
2
vendor/codemirror/README.md
vendored
|
@ -1,4 +1,4 @@
|
|||
## codemirror v5.51.0
|
||||
## codemirror v5.56.0
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
|
|
4
vendor/codemirror/addon/dialog/dialog.js
vendored
4
vendor/codemirror/addon/dialog/dialog.js
vendored
|
@ -82,7 +82,9 @@
|
|||
if (e.keyCode == 13) callback(inp.value, e);
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(dialog, "focusout", function (evt) {
|
||||
if (evt.relatedTarget !== null) close();
|
||||
});
|
||||
} else if (button = dialog.getElementsByTagName("button")[0]) {
|
||||
CodeMirror.on(button, "click", function() {
|
||||
close();
|
||||
|
|
12
vendor/codemirror/addon/edit/matchbrackets.js
vendored
12
vendor/codemirror/addon/edit/matchbrackets.js
vendored
|
@ -118,16 +118,24 @@
|
|||
}
|
||||
|
||||
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.off("cursorActivity", doMatchBrackets);
|
||||
function clear(cm) {
|
||||
if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
|
||||
cm.state.matchBrackets.currentlyHighlighted();
|
||||
cm.state.matchBrackets.currentlyHighlighted = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.off("cursorActivity", doMatchBrackets);
|
||||
cm.off("focus", doMatchBrackets)
|
||||
cm.off("blur", clear)
|
||||
clear(cm);
|
||||
}
|
||||
if (val) {
|
||||
cm.state.matchBrackets = typeof val == "object" ? val : {};
|
||||
cm.on("cursorActivity", doMatchBrackets);
|
||||
cm.on("focus", doMatchBrackets)
|
||||
cm.on("blur", clear)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
35
vendor/codemirror/addon/hint/show-hint.js
vendored
35
vendor/codemirror/addon/hint/show-hint.js
vendored
|
@ -85,11 +85,16 @@
|
|||
},
|
||||
|
||||
pick: function(data, i) {
|
||||
var completion = data.list[i];
|
||||
if (completion.hint) completion.hint(this.cm, data, completion);
|
||||
else this.cm.replaceRange(getText(completion), completion.from || data.from,
|
||||
completion.to || data.to, "complete");
|
||||
CodeMirror.signal(data, "pick", completion);
|
||||
var completion = data.list[i], self = this;
|
||||
this.cm.operation(function() {
|
||||
if (completion.hint)
|
||||
completion.hint(self.cm, data, completion);
|
||||
else
|
||||
self.cm.replaceRange(getText(completion), completion.from || data.from,
|
||||
completion.to || data.to, "complete");
|
||||
CodeMirror.signal(data, "pick", completion);
|
||||
self.cm.scrollIntoView();
|
||||
})
|
||||
this.close();
|
||||
},
|
||||
|
||||
|
@ -99,9 +104,14 @@
|
|||
this.debounce = 0;
|
||||
}
|
||||
|
||||
var identStart = this.startPos;
|
||||
if(this.data) {
|
||||
identStart = this.data.from;
|
||||
}
|
||||
|
||||
var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
|
||||
if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
|
||||
pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
|
||||
pos.ch < identStart.ch || this.cm.somethingSelected() ||
|
||||
(!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
|
||||
this.close();
|
||||
} else {
|
||||
|
@ -369,11 +379,14 @@
|
|||
},
|
||||
|
||||
scrollToActive: function() {
|
||||
var node = this.hints.childNodes[this.selectedHint]
|
||||
if (node.offsetTop < this.hints.scrollTop)
|
||||
this.hints.scrollTop = node.offsetTop - 3;
|
||||
else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
|
||||
this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
|
||||
var margin = this.completion.options.scrollMargin || 0;
|
||||
var node1 = this.hints.childNodes[Math.max(0, this.selectedHint - margin)];
|
||||
var node2 = this.hints.childNodes[Math.min(this.data.list.length - 1, this.selectedHint + margin)];
|
||||
var firstNode = this.hints.firstChild;
|
||||
if (node1.offsetTop < this.hints.scrollTop)
|
||||
this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop;
|
||||
else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
|
||||
this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop;
|
||||
},
|
||||
|
||||
screenAmount: function() {
|
||||
|
|
29
vendor/codemirror/addon/lint/lint.js
vendored
29
vendor/codemirror/addon/lint/lint.js
vendored
|
@ -12,11 +12,14 @@
|
|||
"use strict";
|
||||
var GUTTER_ID = "CodeMirror-lint-markers";
|
||||
|
||||
function showTooltip(e, content) {
|
||||
function showTooltip(cm, e, content) {
|
||||
var tt = document.createElement("div");
|
||||
tt.className = "CodeMirror-lint-tooltip";
|
||||
tt.className = "CodeMirror-lint-tooltip cm-s-" + cm.options.theme;
|
||||
tt.appendChild(content.cloneNode(true));
|
||||
document.body.appendChild(tt);
|
||||
if (cm.state.lint.options.selfContain)
|
||||
cm.getWrapperElement().appendChild(tt);
|
||||
else
|
||||
document.body.appendChild(tt);
|
||||
|
||||
function position(e) {
|
||||
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
|
||||
|
@ -38,8 +41,8 @@
|
|||
setTimeout(function() { rm(tt); }, 600);
|
||||
}
|
||||
|
||||
function showTooltipFor(e, content, node) {
|
||||
var tooltip = showTooltip(e, content);
|
||||
function showTooltipFor(cm, e, content, node) {
|
||||
var tooltip = showTooltip(cm, e, content);
|
||||
function hide() {
|
||||
CodeMirror.off(node, "mouseout", hide);
|
||||
if (tooltip) { hideTooltip(tooltip); tooltip = null; }
|
||||
|
@ -78,7 +81,7 @@
|
|||
state.marked.length = 0;
|
||||
}
|
||||
|
||||
function makeMarker(labels, severity, multiple, tooltips) {
|
||||
function makeMarker(cm, labels, severity, multiple, tooltips) {
|
||||
var marker = document.createElement("div"), inner = marker;
|
||||
marker.className = "CodeMirror-lint-marker-" + severity;
|
||||
if (multiple) {
|
||||
|
@ -87,7 +90,7 @@
|
|||
}
|
||||
|
||||
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
|
||||
showTooltipFor(e, labels, inner);
|
||||
showTooltipFor(cm, e, labels, inner);
|
||||
});
|
||||
|
||||
return marker;
|
||||
|
@ -113,9 +116,9 @@
|
|||
var tip = document.createElement("div");
|
||||
tip.className = "CodeMirror-lint-message-" + severity;
|
||||
if (typeof ann.messageHTML != 'undefined') {
|
||||
tip.innerHTML = ann.messageHTML;
|
||||
tip.innerHTML = ann.messageHTML;
|
||||
} else {
|
||||
tip.appendChild(document.createTextNode(ann.message));
|
||||
tip.appendChild(document.createTextNode(ann.message));
|
||||
}
|
||||
return tip;
|
||||
}
|
||||
|
@ -186,7 +189,7 @@
|
|||
}
|
||||
|
||||
if (state.hasGutter)
|
||||
cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
|
||||
cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, anns.length > 1,
|
||||
state.options.tooltips));
|
||||
}
|
||||
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
|
||||
|
@ -199,14 +202,14 @@
|
|||
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
|
||||
}
|
||||
|
||||
function popupTooltips(annotations, e) {
|
||||
function popupTooltips(cm, annotations, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
var tooltip = document.createDocumentFragment();
|
||||
for (var i = 0; i < annotations.length; i++) {
|
||||
var ann = annotations[i];
|
||||
tooltip.appendChild(annotationTooltip(ann));
|
||||
}
|
||||
showTooltipFor(e, tooltip, target);
|
||||
showTooltipFor(cm, e, tooltip, target);
|
||||
}
|
||||
|
||||
function onMouseOver(cm, e) {
|
||||
|
@ -220,7 +223,7 @@
|
|||
var ann = spans[i].__annotation;
|
||||
if (ann) annotations.push(ann);
|
||||
}
|
||||
if (annotations.length) popupTooltips(annotations, e);
|
||||
if (annotations.length) popupTooltips(cm, annotations, e);
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("lint", false, function(cm, val, old) {
|
||||
|
|
|
@ -240,7 +240,7 @@
|
|||
var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to))
|
||||
|
||||
// Implements weird auto-growing behavior on null-matches for
|
||||
// backwards-compatiblity with the vim code (unfortunately)
|
||||
// backwards-compatibility with the vim code (unfortunately)
|
||||
while (result && CodeMirror.cmpPos(result.from, result.to) == 0) {
|
||||
if (reverse) {
|
||||
if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1)
|
||||
|
|
3
vendor/codemirror/keymap/emacs.js
vendored
3
vendor/codemirror/keymap/emacs.js
vendored
|
@ -404,7 +404,8 @@
|
|||
"Ctrl-X H": "selectAll",
|
||||
|
||||
"Ctrl-Q Tab": repeated("insertTab"),
|
||||
"Ctrl-U": addPrefixMap
|
||||
"Ctrl-U": addPrefixMap,
|
||||
"fallthrough": "default"
|
||||
});
|
||||
|
||||
var prefixMap = {"Ctrl-G": clearPrefix};
|
||||
|
|
2
vendor/codemirror/keymap/sublime.js
vendored
2
vendor/codemirror/keymap/sublime.js
vendored
|
@ -628,6 +628,7 @@
|
|||
"Cmd-K Cmd-C": "showInCenter",
|
||||
"Cmd-K Cmd-G": "clearBookmarks",
|
||||
"Cmd-K Cmd-Backspace": "delLineLeft",
|
||||
"Cmd-K Cmd-1": "foldAll",
|
||||
"Cmd-K Cmd-0": "unfoldAll",
|
||||
"Cmd-K Cmd-J": "unfoldAll",
|
||||
"Ctrl-Shift-Up": "addCursorToPrevLine",
|
||||
|
@ -689,6 +690,7 @@
|
|||
"Ctrl-K Ctrl-C": "showInCenter",
|
||||
"Ctrl-K Ctrl-G": "clearBookmarks",
|
||||
"Ctrl-K Ctrl-Backspace": "delLineLeft",
|
||||
"Ctrl-K Ctrl-1": "foldAll",
|
||||
"Ctrl-K Ctrl-0": "unfoldAll",
|
||||
"Ctrl-K Ctrl-J": "unfoldAll",
|
||||
"Ctrl-Alt-Up": "addCursorToPrevLine",
|
||||
|
|
65
vendor/codemirror/keymap/vim.js
vendored
65
vendor/codemirror/keymap/vim.js
vendored
|
@ -234,7 +234,6 @@
|
|||
{ name: 'undo', shortName: 'u' },
|
||||
{ name: 'redo', shortName: 'red' },
|
||||
{ name: 'set', shortName: 'se' },
|
||||
{ name: 'set', shortName: 'se' },
|
||||
{ name: 'setlocal', shortName: 'setl' },
|
||||
{ name: 'setglobal', shortName: 'setg' },
|
||||
{ name: 'sort', shortName: 'sor' },
|
||||
|
@ -295,16 +294,16 @@
|
|||
clearFatCursorMark(cm);
|
||||
var ranges = cm.listSelections(), result = []
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i]
|
||||
var range = ranges[i];
|
||||
if (range.empty()) {
|
||||
if (range.anchor.ch < cm.getLine(range.anchor.line).length) {
|
||||
var lineLength = cm.getLine(range.anchor.line).length;
|
||||
if (range.anchor.ch < lineLength) {
|
||||
result.push(cm.markText(range.anchor, Pos(range.anchor.line, range.anchor.ch + 1),
|
||||
{className: "cm-fat-cursor-mark"}))
|
||||
{className: "cm-fat-cursor-mark"}));
|
||||
} else {
|
||||
var widget = document.createElement("span")
|
||||
widget.textContent = "\u00a0"
|
||||
widget.className = "cm-fat-cursor-mark"
|
||||
result.push(cm.setBookmark(range.anchor, {widget: widget}))
|
||||
result.push(cm.markText(Pos(range.anchor.line, lineLength - 1),
|
||||
Pos(range.anchor.line, lineLength),
|
||||
{className: "cm-fat-cursor-mark"}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1603,10 +1602,10 @@
|
|||
}
|
||||
if (vim.visualMode) {
|
||||
if (!(vim.visualBlock && newHead.ch === Infinity)) {
|
||||
newHead = clipCursorToContent(cm, newHead, vim.visualBlock);
|
||||
newHead = clipCursorToContent(cm, newHead);
|
||||
}
|
||||
if (newAnchor) {
|
||||
newAnchor = clipCursorToContent(cm, newAnchor, true);
|
||||
newAnchor = clipCursorToContent(cm, newAnchor);
|
||||
}
|
||||
newAnchor = newAnchor || oldAnchor;
|
||||
sel.anchor = newAnchor;
|
||||
|
@ -2200,8 +2199,7 @@
|
|||
vimGlobalState.registerController.pushText(
|
||||
args.registerName, 'delete', text,
|
||||
args.linewise, vim.visualBlock);
|
||||
var includeLineBreak = vim.insertMode
|
||||
return clipCursorToContent(cm, finalHead, includeLineBreak);
|
||||
return clipCursorToContent(cm, finalHead);
|
||||
},
|
||||
indent: function(cm, args, ranges) {
|
||||
var vim = cm.state.vim;
|
||||
|
@ -2460,8 +2458,7 @@
|
|||
vim.visualLine = !!actionArgs.linewise;
|
||||
vim.visualBlock = !!actionArgs.blockwise;
|
||||
head = clipCursorToContent(
|
||||
cm, Pos(anchor.line, anchor.ch + repeat - 1),
|
||||
true /** includeLineBreak */);
|
||||
cm, Pos(anchor.line, anchor.ch + repeat - 1));
|
||||
vim.sel = {
|
||||
anchor: anchor,
|
||||
head: head
|
||||
|
@ -2837,10 +2834,11 @@
|
|||
* Clips cursor to ensure that line is within the buffer's range
|
||||
* If includeLineBreak is true, then allow cur.ch == lineLength.
|
||||
*/
|
||||
function clipCursorToContent(cm, cur, includeLineBreak) {
|
||||
function clipCursorToContent(cm, cur) {
|
||||
var vim = cm.state.vim;
|
||||
var includeLineBreak = vim.insertMode || vim.visualMode;
|
||||
var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() );
|
||||
var maxCh = lineLength(cm, line) - 1;
|
||||
maxCh = (includeLineBreak) ? maxCh + 1 : maxCh;
|
||||
var maxCh = lineLength(cm, line) - 1 + !!includeLineBreak;
|
||||
var ch = Math.min(Math.max(0, cur.ch), maxCh);
|
||||
return Pos(line, ch);
|
||||
}
|
||||
|
@ -3205,10 +3203,8 @@
|
|||
vim.visualMode = false;
|
||||
vim.visualLine = false;
|
||||
vim.visualBlock = false;
|
||||
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
||||
if (vim.fakeCursor) {
|
||||
vim.fakeCursor.clear();
|
||||
}
|
||||
if (!vim.insertMode) CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
||||
clearFakeCursor(vim);
|
||||
}
|
||||
|
||||
// Remove any trailing newlines from the selection. For
|
||||
|
@ -4186,7 +4182,8 @@
|
|||
}
|
||||
function makePrompt(prefix, desc) {
|
||||
var raw = '<span style="font-family: monospace; white-space: pre">' +
|
||||
(prefix || "") + '<input type="text"></span>';
|
||||
(prefix || "") + '<input type="text" autocorrect="off" ' +
|
||||
'autocapitalize="off" spellcheck="false"></span>';
|
||||
if (desc)
|
||||
raw += ' <span style="color: #888">' + desc + '</span>';
|
||||
return raw;
|
||||
|
@ -4459,7 +4456,7 @@
|
|||
}
|
||||
|
||||
// Parse command name.
|
||||
var commandMatch = inputStream.match(/^(\w+)/);
|
||||
var commandMatch = inputStream.match(/^(\w+|!!|@@|[!#&*<=>@~])/);
|
||||
if (commandMatch) {
|
||||
result.commandName = commandMatch[1];
|
||||
} else {
|
||||
|
@ -5357,14 +5354,34 @@
|
|||
updateFakeCursor(cm);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Keeps track of a fake cursor to support visual mode cursor behavior.
|
||||
*/
|
||||
function updateFakeCursor(cm) {
|
||||
var className = 'cm-animate-fat-cursor';
|
||||
var vim = cm.state.vim;
|
||||
var from = clipCursorToContent(cm, copyCursor(vim.sel.head));
|
||||
var to = offsetCursor(from, 0, 1);
|
||||
clearFakeCursor(vim);
|
||||
// In visual mode, the cursor may be positioned over EOL.
|
||||
if (from.ch == cm.getLine(from.line).length) {
|
||||
var widget = document.createElement("span");
|
||||
widget.textContent = "\u00a0";
|
||||
widget.className = className;
|
||||
vim.fakeCursorBookmark = cm.setBookmark(from, {widget: widget});
|
||||
} else {
|
||||
vim.fakeCursor = cm.markText(from, to, {className: className});
|
||||
}
|
||||
}
|
||||
function clearFakeCursor(vim) {
|
||||
if (vim.fakeCursor) {
|
||||
vim.fakeCursor.clear();
|
||||
vim.fakeCursor = null;
|
||||
}
|
||||
if (vim.fakeCursorBookmark) {
|
||||
vim.fakeCursorBookmark.clear();
|
||||
vim.fakeCursorBookmark = null;
|
||||
}
|
||||
vim.fakeCursor = cm.markText(from, to, {className: 'cm-animate-fat-cursor'});
|
||||
}
|
||||
function handleExternalSelection(cm, vim) {
|
||||
var anchor = cm.getCursor('anchor');
|
||||
|
|
10
vendor/codemirror/lib/codemirror.css
vendored
10
vendor/codemirror/lib/codemirror.css
vendored
|
@ -164,17 +164,17 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
|
|||
|
||||
.CodeMirror-scroll {
|
||||
overflow: scroll !important; /* Things will break if this is overridden */
|
||||
/* 30px is the magic margin used to hide the element's real scrollbars */
|
||||
/* 50px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -30px; margin-right: -30px;
|
||||
padding-bottom: 30px;
|
||||
margin-bottom: -50px; margin-right: -50px;
|
||||
padding-bottom: 50px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 30px solid transparent;
|
||||
border-right: 50px solid transparent;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
|
@ -212,7 +212,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
|
|||
height: 100%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom: -30px;
|
||||
margin-bottom: -50px;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
position: absolute;
|
||||
|
|
86
vendor/codemirror/lib/codemirror.js
vendored
86
vendor/codemirror/lib/codemirror.js
vendored
|
@ -204,7 +204,7 @@
|
|||
}
|
||||
|
||||
// Number of pixels added to scroller and sizer to hide scrollbar
|
||||
var scrollerGap = 30;
|
||||
var scrollerGap = 50;
|
||||
|
||||
// Returned or thrown by various protocols to signal 'I'm not
|
||||
// handling this'.
|
||||
|
@ -485,14 +485,15 @@
|
|||
for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
|
||||
order.push(new BidiSpan(0, start, i$7));
|
||||
} else {
|
||||
var pos = i$7, at = order.length;
|
||||
var pos = i$7, at = order.length, isRTL = direction == "rtl" ? 1 : 0;
|
||||
for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
|
||||
for (var j$2 = pos; j$2 < i$7;) {
|
||||
if (countsAsNum.test(types[j$2])) {
|
||||
if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
|
||||
if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); at += isRTL; }
|
||||
var nstart = j$2;
|
||||
for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
|
||||
order.splice(at, 0, new BidiSpan(2, nstart, j$2));
|
||||
at += isRTL;
|
||||
pos = j$2;
|
||||
} else { ++j$2; }
|
||||
}
|
||||
|
@ -1200,7 +1201,7 @@
|
|||
var prop = lineClass[1] ? "bgClass" : "textClass";
|
||||
if (output[prop] == null)
|
||||
{ output[prop] = lineClass[2]; }
|
||||
else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
|
||||
else if (!(new RegExp("(?:^|\\s)" + lineClass[2] + "(?:$|\\s)")).test(output[prop]))
|
||||
{ output[prop] += " " + lineClass[2]; }
|
||||
} }
|
||||
return type
|
||||
|
@ -2959,7 +2960,7 @@
|
|||
var x, y, space = display.lineSpace.getBoundingClientRect();
|
||||
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
|
||||
try { x = e.clientX - space.left; y = e.clientY - space.top; }
|
||||
catch (e) { return null }
|
||||
catch (e$1) { return null }
|
||||
var coords = coordsChar(cm, x, y), line;
|
||||
if (forRect && coords.xRel > 0 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
|
||||
var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
|
||||
|
@ -3550,7 +3551,7 @@
|
|||
}
|
||||
|
||||
function setScrollTop(cm, val, forceScroll) {
|
||||
val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
|
||||
val = Math.max(0, Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val));
|
||||
if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
|
||||
cm.doc.scrollTop = val;
|
||||
cm.display.scrollbars.setScrollTop(val);
|
||||
|
@ -3560,7 +3561,7 @@
|
|||
// Sync scroller and scrollbar, ensure the gutter elements are
|
||||
// aligned.
|
||||
function setScrollLeft(cm, val, isScroller, forceScroll) {
|
||||
val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
|
||||
val = Math.max(0, Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth));
|
||||
if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
|
||||
cm.doc.scrollLeft = val;
|
||||
alignHorizontally(cm);
|
||||
|
@ -4049,7 +4050,8 @@
|
|||
function restoreSelection(snapshot) {
|
||||
if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
|
||||
snapshot.activeElt.focus();
|
||||
if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
|
||||
if (!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) &&
|
||||
snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
|
||||
var sel = window.getSelection(), range = document.createRange();
|
||||
range.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
|
||||
range.collapse(false);
|
||||
|
@ -4147,6 +4149,8 @@
|
|||
update.visible = visibleLines(cm.display, cm.doc, viewport);
|
||||
if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
|
||||
{ break }
|
||||
} else if (first) {
|
||||
update.visible = visibleLines(cm.display, cm.doc, viewport);
|
||||
}
|
||||
if (!updateDisplayIfNeeded(cm, update)) { break }
|
||||
updateHeightsInViewport(cm);
|
||||
|
@ -6496,7 +6500,7 @@
|
|||
text.filter(function (t) { return t != null; }).join(cm.doc.lineSeparator())),
|
||||
origin: "paste"};
|
||||
makeChange(cm.doc, change);
|
||||
setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
|
||||
setSelectionReplaceHistory(cm.doc, simpleSelection(clipPos(cm.doc, pos), clipPos(cm.doc, changeEnd(change))));
|
||||
})();
|
||||
}
|
||||
};
|
||||
|
@ -6541,7 +6545,7 @@
|
|||
cm.display.input.focus();
|
||||
}
|
||||
}
|
||||
catch(e){}
|
||||
catch(e$1){}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6829,7 +6833,7 @@
|
|||
|
||||
function endOfLine(visually, cm, lineObj, lineNo, dir) {
|
||||
if (visually) {
|
||||
if (cm.getOption("direction") == "rtl") { dir = -dir; }
|
||||
if (cm.doc.direction == "rtl") { dir = -dir; }
|
||||
var order = getOrder(lineObj, cm.doc.direction);
|
||||
if (order) {
|
||||
var part = dir < 0 ? lst(order) : order[0];
|
||||
|
@ -7084,7 +7088,7 @@
|
|||
var line = getLine(cm.doc, start.line);
|
||||
var order = getOrder(line, cm.doc.direction);
|
||||
if (!order || order[0].level == 0) {
|
||||
var firstNonWS = Math.max(0, line.text.search(/\S/));
|
||||
var firstNonWS = Math.max(start.ch, line.text.search(/\S/));
|
||||
var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
|
||||
return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
|
||||
}
|
||||
|
@ -7187,6 +7191,7 @@
|
|||
var lastStoppedKey = null;
|
||||
function onKeyDown(e) {
|
||||
var cm = this;
|
||||
if (e.target && e.target != cm.display.input.getField()) { return }
|
||||
cm.curOp.focus = activeElt();
|
||||
if (signalDOMEvent(cm, e)) { return }
|
||||
// IE does strange things with escape.
|
||||
|
@ -7230,6 +7235,7 @@
|
|||
|
||||
function onKeyPress(e) {
|
||||
var cm = this;
|
||||
if (e.target && e.target != cm.display.input.getField()) { return }
|
||||
if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
|
||||
var keyCode = e.keyCode, charCode = e.charCode;
|
||||
if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
|
||||
|
@ -7378,8 +7384,8 @@
|
|||
if (!behavior.addNew)
|
||||
{ extendSelection(cm.doc, pos, null, null, behavior.extend); }
|
||||
// Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
|
||||
if (webkit || ie && ie_version == 9)
|
||||
{ setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); }
|
||||
if ((webkit && !safari) || ie && ie_version == 9)
|
||||
{ setTimeout(function () {display.wrapper.ownerDocument.body.focus({preventScroll: true}); display.input.focus();}, 20); }
|
||||
else
|
||||
{ display.input.focus(); }
|
||||
}
|
||||
|
@ -7591,7 +7597,7 @@
|
|||
mY = e.touches[0].clientY;
|
||||
} else {
|
||||
try { mX = e.clientX; mY = e.clientY; }
|
||||
catch(e) { return false }
|
||||
catch(e$1) { return false }
|
||||
}
|
||||
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
|
||||
if (prevent) { e_preventDefault(e); }
|
||||
|
@ -7691,7 +7697,7 @@
|
|||
for (var i = newBreaks.length - 1; i >= 0; i--)
|
||||
{ replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
|
||||
});
|
||||
option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) {
|
||||
option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200c\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) {
|
||||
cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
|
||||
if (old != Init) { cm.refresh(); }
|
||||
});
|
||||
|
@ -7755,6 +7761,12 @@
|
|||
}
|
||||
cm.display.input.readOnlyChanged(val);
|
||||
});
|
||||
|
||||
option("screenReaderLabel", null, function (cm, val) {
|
||||
val = (val === '') ? null : val;
|
||||
cm.display.input.screenReaderLabelChanged(val);
|
||||
});
|
||||
|
||||
option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
|
||||
option("dragDrop", true, dragDropChanged);
|
||||
option("allowDropFileTypes", null);
|
||||
|
@ -8105,7 +8117,7 @@
|
|||
{ from = Pos(from.line, from.ch - deleted); }
|
||||
else if (cm.state.overwrite && !paste) // Handle overwrite
|
||||
{ to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
|
||||
else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
|
||||
else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == textLines.join("\n"))
|
||||
{ from = to = Pos(from.line, 0); }
|
||||
}
|
||||
var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
|
||||
|
@ -8586,7 +8598,7 @@
|
|||
clearCaches(this);
|
||||
scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
|
||||
updateGutterSpace(this.display);
|
||||
if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
|
||||
if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5 || this.options.lineWrapping)
|
||||
{ estimateLineHeights(this); }
|
||||
signal(this, "refresh", this);
|
||||
}),
|
||||
|
@ -8640,7 +8652,7 @@
|
|||
var oldPos = pos;
|
||||
var origDir = dir;
|
||||
var lineObj = getLine(doc, pos.line);
|
||||
var lineDir = visually && doc.cm && doc.cm.getOption("direction") == "rtl" ? -dir : dir;
|
||||
var lineDir = visually && doc.direction == "rtl" ? -dir : dir;
|
||||
function findNextLine() {
|
||||
var l = pos.line + lineDir;
|
||||
if (l < doc.first || l >= doc.first + doc.size) { return false }
|
||||
|
@ -8735,8 +8747,16 @@
|
|||
var div = input.div = display.lineDiv;
|
||||
disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize);
|
||||
|
||||
function belongsToInput(e) {
|
||||
for (var t = e.target; t; t = t.parentNode) {
|
||||
if (t == div) { return true }
|
||||
if (/\bCodeMirror-(?:line)?widget\b/.test(t.className)) { break }
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
on(div, "paste", function (e) {
|
||||
if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
|
||||
if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
|
||||
// IE doesn't fire input events, so we schedule a read for the pasted content in this way
|
||||
if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
|
||||
});
|
||||
|
@ -8761,7 +8781,7 @@
|
|||
});
|
||||
|
||||
function onCopyCut(e) {
|
||||
if (signalDOMEvent(cm, e)) { return }
|
||||
if (!belongsToInput(e) || signalDOMEvent(cm, e)) { return }
|
||||
if (cm.somethingSelected()) {
|
||||
setLastCopied({lineWise: false, text: cm.getSelections()});
|
||||
if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
|
||||
|
@ -8803,9 +8823,18 @@
|
|||
on(div, "cut", onCopyCut);
|
||||
};
|
||||
|
||||
ContentEditableInput.prototype.screenReaderLabelChanged = function (label) {
|
||||
// Label for screenreaders, accessibility
|
||||
if(label) {
|
||||
this.div.setAttribute('aria-label', label);
|
||||
} else {
|
||||
this.div.removeAttribute('aria-label');
|
||||
}
|
||||
};
|
||||
|
||||
ContentEditableInput.prototype.prepareSelection = function () {
|
||||
var result = prepareSelection(this.cm, false);
|
||||
result.focus = this.cm.state.focused;
|
||||
result.focus = document.activeElement == this.div;
|
||||
return result
|
||||
};
|
||||
|
||||
|
@ -8901,7 +8930,7 @@
|
|||
|
||||
ContentEditableInput.prototype.focus = function () {
|
||||
if (this.cm.options.readOnly != "nocursor") {
|
||||
if (!this.selectionInEditor())
|
||||
if (!this.selectionInEditor() || document.activeElement != this.div)
|
||||
{ this.showSelection(this.prepareSelection(), true); }
|
||||
this.div.focus();
|
||||
}
|
||||
|
@ -9343,6 +9372,15 @@
|
|||
this.textarea = this.wrapper.firstChild;
|
||||
};
|
||||
|
||||
TextareaInput.prototype.screenReaderLabelChanged = function (label) {
|
||||
// Label for screenreaders, accessibility
|
||||
if(label) {
|
||||
this.textarea.setAttribute('aria-label', label);
|
||||
} else {
|
||||
this.textarea.removeAttribute('aria-label');
|
||||
}
|
||||
};
|
||||
|
||||
TextareaInput.prototype.prepareSelection = function () {
|
||||
// Redraw the selection and/or cursor
|
||||
var cm = this.cm, display = cm.display, doc = cm.doc;
|
||||
|
@ -9733,7 +9771,7 @@
|
|||
|
||||
addLegacyProps(CodeMirror);
|
||||
|
||||
CodeMirror.version = "5.51.0";
|
||||
CodeMirror.version = "5.56.0";
|
||||
|
||||
return CodeMirror;
|
||||
|
||||
|
|
181
vendor/codemirror/mode/css/css.js
vendored
181
vendor/codemirror/mode/css/css.js
vendored
|
@ -455,81 +455,98 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
|||
"alignment-baseline", "anchor-point", "animation", "animation-delay",
|
||||
"animation-direction", "animation-duration", "animation-fill-mode",
|
||||
"animation-iteration-count", "animation-name", "animation-play-state",
|
||||
"animation-timing-function", "appearance", "azimuth", "backface-visibility",
|
||||
"background", "background-attachment", "background-blend-mode", "background-clip",
|
||||
"background-color", "background-image", "background-origin", "background-position",
|
||||
"background-repeat", "background-size", "baseline-shift", "binding",
|
||||
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
|
||||
"bookmark-target", "border", "border-bottom", "border-bottom-color",
|
||||
"border-bottom-left-radius", "border-bottom-right-radius",
|
||||
"border-bottom-style", "border-bottom-width", "border-collapse",
|
||||
"border-color", "border-image", "border-image-outset",
|
||||
"animation-timing-function", "appearance", "azimuth", "backdrop-filter",
|
||||
"backface-visibility", "background", "background-attachment",
|
||||
"background-blend-mode", "background-clip", "background-color",
|
||||
"background-image", "background-origin", "background-position",
|
||||
"background-position-x", "background-position-y", "background-repeat",
|
||||
"background-size", "baseline-shift", "binding", "bleed", "block-size",
|
||||
"bookmark-label", "bookmark-level", "bookmark-state", "bookmark-target",
|
||||
"border", "border-bottom", "border-bottom-color", "border-bottom-left-radius",
|
||||
"border-bottom-right-radius", "border-bottom-style", "border-bottom-width",
|
||||
"border-collapse", "border-color", "border-image", "border-image-outset",
|
||||
"border-image-repeat", "border-image-slice", "border-image-source",
|
||||
"border-image-width", "border-left", "border-left-color",
|
||||
"border-left-style", "border-left-width", "border-radius", "border-right",
|
||||
"border-right-color", "border-right-style", "border-right-width",
|
||||
"border-spacing", "border-style", "border-top", "border-top-color",
|
||||
"border-top-left-radius", "border-top-right-radius", "border-top-style",
|
||||
"border-top-width", "border-width", "bottom", "box-decoration-break",
|
||||
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
|
||||
"caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
|
||||
"column-fill", "column-gap", "column-rule", "column-rule-color",
|
||||
"column-rule-style", "column-rule-width", "column-span", "column-width",
|
||||
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
|
||||
"cue-after", "cue-before", "cursor", "direction", "display",
|
||||
"dominant-baseline", "drop-initial-after-adjust",
|
||||
"drop-initial-after-align", "drop-initial-before-adjust",
|
||||
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
|
||||
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
|
||||
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
|
||||
"float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
|
||||
"font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
|
||||
"font-stretch", "font-style", "font-synthesis", "font-variant",
|
||||
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
|
||||
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
|
||||
"font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
|
||||
"grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
|
||||
"grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
|
||||
"grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
|
||||
"grid-template-rows", "hanging-punctuation", "height", "hyphens",
|
||||
"icon", "image-orientation", "image-rendering", "image-resolution",
|
||||
"inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
|
||||
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
|
||||
"border-image-width", "border-left", "border-left-color", "border-left-style",
|
||||
"border-left-width", "border-radius", "border-right", "border-right-color",
|
||||
"border-right-style", "border-right-width", "border-spacing", "border-style",
|
||||
"border-top", "border-top-color", "border-top-left-radius",
|
||||
"border-top-right-radius", "border-top-style", "border-top-width",
|
||||
"border-width", "bottom", "box-decoration-break", "box-shadow", "box-sizing",
|
||||
"break-after", "break-before", "break-inside", "caption-side", "caret-color",
|
||||
"clear", "clip", "color", "color-profile", "column-count", "column-fill",
|
||||
"column-gap", "column-rule", "column-rule-color", "column-rule-style",
|
||||
"column-rule-width", "column-span", "column-width", "columns", "contain",
|
||||
"content", "counter-increment", "counter-reset", "crop", "cue", "cue-after",
|
||||
"cue-before", "cursor", "direction", "display", "dominant-baseline",
|
||||
"drop-initial-after-adjust", "drop-initial-after-align",
|
||||
"drop-initial-before-adjust", "drop-initial-before-align", "drop-initial-size",
|
||||
"drop-initial-value", "elevation", "empty-cells", "fit", "fit-position",
|
||||
"flex", "flex-basis", "flex-direction", "flex-flow", "flex-grow",
|
||||
"flex-shrink", "flex-wrap", "float", "float-offset", "flow-from", "flow-into",
|
||||
"font", "font-family", "font-feature-settings", "font-kerning",
|
||||
"font-language-override", "font-optical-sizing", "font-size",
|
||||
"font-size-adjust", "font-stretch", "font-style", "font-synthesis",
|
||||
"font-variant", "font-variant-alternates", "font-variant-caps",
|
||||
"font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric",
|
||||
"font-variant-position", "font-variation-settings", "font-weight", "gap",
|
||||
"grid", "grid-area", "grid-auto-columns", "grid-auto-flow", "grid-auto-rows",
|
||||
"grid-column", "grid-column-end", "grid-column-gap", "grid-column-start",
|
||||
"grid-gap", "grid-row", "grid-row-end", "grid-row-gap", "grid-row-start",
|
||||
"grid-template", "grid-template-areas", "grid-template-columns",
|
||||
"grid-template-rows", "hanging-punctuation", "height", "hyphens", "icon",
|
||||
"image-orientation", "image-rendering", "image-resolution", "inline-box-align",
|
||||
"inset", "inset-block", "inset-block-end", "inset-block-start", "inset-inline",
|
||||
"inset-inline-end", "inset-inline-start", "isolation", "justify-content",
|
||||
"justify-items", "justify-self", "left", "letter-spacing", "line-break",
|
||||
"line-height", "line-height-step", "line-stacking", "line-stacking-ruby",
|
||||
"line-stacking-shift", "line-stacking-strategy", "list-style",
|
||||
"list-style-image", "list-style-position", "list-style-type", "margin",
|
||||
"margin-bottom", "margin-left", "margin-right", "margin-top",
|
||||
"marks", "marquee-direction", "marquee-loop",
|
||||
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
|
||||
"max-width", "min-height", "min-width", "mix-blend-mode", "move-to", "nav-down", "nav-index",
|
||||
"nav-left", "nav-right", "nav-up", "object-fit", "object-position",
|
||||
"opacity", "order", "orphans", "outline",
|
||||
"outline-color", "outline-offset", "outline-style", "outline-width",
|
||||
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
|
||||
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
|
||||
"page", "page-break-after", "page-break-before", "page-break-inside",
|
||||
"page-policy", "pause", "pause-after", "pause-before", "perspective",
|
||||
"perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
|
||||
"presentation-level", "punctuation-trim", "quotes", "region-break-after",
|
||||
"region-break-before", "region-break-inside", "region-fragment",
|
||||
"rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
|
||||
"right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
|
||||
"ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
|
||||
"shape-outside", "size", "speak", "speak-as", "speak-header",
|
||||
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
|
||||
"tab-size", "table-layout", "target", "target-name", "target-new",
|
||||
"target-position", "text-align", "text-align-last", "text-decoration",
|
||||
"margin-bottom", "margin-left", "margin-right", "margin-top", "marks",
|
||||
"marquee-direction", "marquee-loop", "marquee-play-count", "marquee-speed",
|
||||
"marquee-style", "max-block-size", "max-height", "max-inline-size",
|
||||
"max-width", "min-block-size", "min-height", "min-inline-size", "min-width",
|
||||
"mix-blend-mode", "move-to", "nav-down", "nav-index", "nav-left", "nav-right",
|
||||
"nav-up", "object-fit", "object-position", "offset", "offset-anchor",
|
||||
"offset-distance", "offset-path", "offset-position", "offset-rotate",
|
||||
"opacity", "order", "orphans", "outline", "outline-color", "outline-offset",
|
||||
"outline-style", "outline-width", "overflow", "overflow-style",
|
||||
"overflow-wrap", "overflow-x", "overflow-y", "padding", "padding-bottom",
|
||||
"padding-left", "padding-right", "padding-top", "page", "page-break-after",
|
||||
"page-break-before", "page-break-inside", "page-policy", "pause",
|
||||
"pause-after", "pause-before", "perspective", "perspective-origin", "pitch",
|
||||
"pitch-range", "place-content", "place-items", "place-self", "play-during",
|
||||
"position", "presentation-level", "punctuation-trim", "quotes",
|
||||
"region-break-after", "region-break-before", "region-break-inside",
|
||||
"region-fragment", "rendering-intent", "resize", "rest", "rest-after",
|
||||
"rest-before", "richness", "right", "rotate", "rotation", "rotation-point",
|
||||
"row-gap", "ruby-align", "ruby-overhang", "ruby-position", "ruby-span",
|
||||
"scale", "scroll-behavior", "scroll-margin", "scroll-margin-block",
|
||||
"scroll-margin-block-end", "scroll-margin-block-start", "scroll-margin-bottom",
|
||||
"scroll-margin-inline", "scroll-margin-inline-end",
|
||||
"scroll-margin-inline-start", "scroll-margin-left", "scroll-margin-right",
|
||||
"scroll-margin-top", "scroll-padding", "scroll-padding-block",
|
||||
"scroll-padding-block-end", "scroll-padding-block-start",
|
||||
"scroll-padding-bottom", "scroll-padding-inline", "scroll-padding-inline-end",
|
||||
"scroll-padding-inline-start", "scroll-padding-left", "scroll-padding-right",
|
||||
"scroll-padding-top", "scroll-snap-align", "scroll-snap-type",
|
||||
"shape-image-threshold", "shape-inside", "shape-margin", "shape-outside",
|
||||
"size", "speak", "speak-as", "speak-header", "speak-numeral",
|
||||
"speak-punctuation", "speech-rate", "stress", "string-set", "tab-size",
|
||||
"table-layout", "target", "target-name", "target-new", "target-position",
|
||||
"text-align", "text-align-last", "text-combine-upright", "text-decoration",
|
||||
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
|
||||
"text-decoration-style", "text-emphasis", "text-emphasis-color",
|
||||
"text-emphasis-position", "text-emphasis-style", "text-height",
|
||||
"text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
|
||||
"text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
|
||||
"text-wrap", "top", "transform", "transform-origin", "transform-style",
|
||||
"transition", "transition-delay", "transition-duration",
|
||||
"transition-property", "transition-timing-function", "unicode-bidi",
|
||||
"user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
|
||||
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
|
||||
"voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
|
||||
"word-spacing", "word-wrap", "z-index",
|
||||
"text-decoration-skip-ink", "text-decoration-style", "text-emphasis",
|
||||
"text-emphasis-color", "text-emphasis-position", "text-emphasis-style",
|
||||
"text-height", "text-indent", "text-justify", "text-orientation",
|
||||
"text-outline", "text-overflow", "text-rendering", "text-shadow",
|
||||
"text-size-adjust", "text-space-collapse", "text-transform",
|
||||
"text-underline-position", "text-wrap", "top", "transform", "transform-origin",
|
||||
"transform-style", "transition", "transition-delay", "transition-duration",
|
||||
"transition-property", "transition-timing-function", "translate",
|
||||
"unicode-bidi", "user-select", "vertical-align", "visibility", "voice-balance",
|
||||
"voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate",
|
||||
"voice-stress", "voice-volume", "volume", "white-space", "widows", "width",
|
||||
"will-change", "word-break", "word-spacing", "word-wrap", "writing-mode", "z-index",
|
||||
// SVG-specific
|
||||
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
|
||||
"flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
|
||||
|
@ -543,16 +560,28 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
|||
], propertyKeywords = keySet(propertyKeywords_);
|
||||
|
||||
var nonStandardPropertyKeywords_ = [
|
||||
"border-block", "border-block-color", "border-block-end",
|
||||
"border-block-end-color", "border-block-end-style", "border-block-end-width",
|
||||
"border-block-start", "border-block-start-color", "border-block-start-style",
|
||||
"border-block-start-width", "border-block-style", "border-block-width",
|
||||
"border-inline", "border-inline-color", "border-inline-end",
|
||||
"border-inline-end-color", "border-inline-end-style",
|
||||
"border-inline-end-width", "border-inline-start", "border-inline-start-color",
|
||||
"border-inline-start-style", "border-inline-start-width",
|
||||
"border-inline-style", "border-inline-width", "margin-block",
|
||||
"margin-block-end", "margin-block-start", "margin-inline", "margin-inline-end",
|
||||
"margin-inline-start", "padding-block", "padding-block-end",
|
||||
"padding-block-start", "padding-inline", "padding-inline-end",
|
||||
"padding-inline-start", "scroll-snap-stop", "scrollbar-3d-light-color",
|
||||
"scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
|
||||
"scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
|
||||
"scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
|
||||
"searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
|
||||
"searchfield-results-decoration", "zoom"
|
||||
"scrollbar-track-color", "searchfield-cancel-button", "searchfield-decoration",
|
||||
"searchfield-results-button", "searchfield-results-decoration", "shape-inside", "zoom"
|
||||
], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
|
||||
|
||||
var fontProperties_ = [
|
||||
"font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
|
||||
"font-stretch", "font-weight", "font-style"
|
||||
"font-display", "font-family", "src", "unicode-range", "font-variant",
|
||||
"font-feature-settings", "font-stretch", "font-weight", "font-style"
|
||||
], fontProperties = keySet(fontProperties_);
|
||||
|
||||
var counterDescriptors_ = [
|
||||
|
|
22
vendor/codemirror/mode/javascript/javascript.js
vendored
22
vendor/codemirror/mode/javascript/javascript.js
vendored
|
@ -98,10 +98,13 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
} else if (ch == "`") {
|
||||
state.tokenize = tokenQuasi;
|
||||
return tokenQuasi(stream, state);
|
||||
} else if (ch == "#") {
|
||||
} else if (ch == "#" && stream.peek() == "!") {
|
||||
stream.skipToEnd();
|
||||
return ret("error", "error");
|
||||
} else if (ch == "<" && stream.match("!--") || ch == "-" && stream.match("->")) {
|
||||
return ret("meta", "meta");
|
||||
} else if (ch == "#" && stream.eatWhile(wordRE)) {
|
||||
return ret("variable", "property")
|
||||
} else if (ch == "<" && stream.match("!--") ||
|
||||
(ch == "-" && stream.match("->") && !/\S/.test(stream.string.slice(0, stream.start)))) {
|
||||
stream.skipToEnd()
|
||||
return ret("comment", "comment")
|
||||
} else if (isOperatorChar.test(ch)) {
|
||||
|
@ -113,6 +116,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (ch == ">") stream.eat(ch)
|
||||
}
|
||||
}
|
||||
if (ch == "?" && stream.eat(".")) return ret(".")
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else if (wordRE.test(ch)) {
|
||||
stream.eatWhile(wordRE);
|
||||
|
@ -417,7 +421,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
}
|
||||
function parenExpr(type) {
|
||||
if (type != "(") return pass()
|
||||
return cont(pushlex(")"), expression, expect(")"), poplex)
|
||||
return cont(pushlex(")"), maybeexpression, expect(")"), poplex)
|
||||
}
|
||||
function expressionInner(type, value, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
|
@ -446,7 +450,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
}
|
||||
|
||||
function maybeoperatorComma(type, value) {
|
||||
if (type == ",") return cont(expression);
|
||||
if (type == ",") return cont(maybeexpression);
|
||||
return maybeoperatorNoComma(type, value, false);
|
||||
}
|
||||
function maybeoperatorNoComma(type, value, noComma) {
|
||||
|
@ -455,7 +459,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
|
||||
if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false))
|
||||
if (isTS && value == "<" && cx.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/, false))
|
||||
return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);
|
||||
if (value == "?") return cont(expression, expect(":"), expr);
|
||||
return cont(expr);
|
||||
|
@ -757,11 +761,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
}
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
return cont(isTS ? classfield : functiondef, classBody);
|
||||
return cont(classfield, classBody);
|
||||
}
|
||||
if (type == "number" || type == "string") return cont(isTS ? classfield : functiondef, classBody);
|
||||
if (type == "number" || type == "string") return cont(classfield, classBody);
|
||||
if (type == "[")
|
||||
return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody)
|
||||
return cont(expression, maybetype, expect("]"), classfield, classBody)
|
||||
if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
|
|
2
vendor/codemirror/mode/stylus/stylus.js
vendored
2
vendor/codemirror/mode/stylus/stylus.js
vendored
|
@ -76,7 +76,7 @@
|
|||
if (ch == "#") {
|
||||
stream.next();
|
||||
// Hex color
|
||||
if (stream.match(/^[0-9a-f]{3}([0-9a-f]([0-9a-f]{2}){0,2})?\b/i)) {
|
||||
if (stream.match(/^[0-9a-f]{3}([0-9a-f]([0-9a-f]{2}){0,2})?\b(?!-)/i)) {
|
||||
return ["atom", "atom"];
|
||||
}
|
||||
// ID selector
|
||||
|
|
2
vendor/codemirror/theme/zenburn.css
vendored
2
vendor/codemirror/theme/zenburn.css
vendored
|
@ -11,7 +11,7 @@
|
|||
.cm-s-zenburn .CodeMirror-gutters { background: #3f3f3f !important; }
|
||||
.cm-s-zenburn .CodeMirror-foldgutter-open, .CodeMirror-foldgutter-folded { color: #999; }
|
||||
.cm-s-zenburn .CodeMirror-cursor { border-left: 1px solid white; }
|
||||
.cm-s-zenburn { background-color: #3f3f3f; color: #dcdccc; }
|
||||
.cm-s-zenburn.CodeMirror { background-color: #3f3f3f; color: #dcdccc; }
|
||||
.cm-s-zenburn span.cm-builtin { color: #dcdccc; font-weight: bold; }
|
||||
.cm-s-zenburn span.cm-comment { color: #7f9f7f; }
|
||||
.cm-s-zenburn span.cm-keyword { color: #f0dfaf; font-weight: bold; }
|
||||
|
|
2
vendor/uuid/LICENSE
vendored
2
vendor/uuid/LICENSE
vendored
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2010-2016 Robert Kieffer and other contributors
|
||||
Copyright (c) 2010-2020 Robert Kieffer and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
2
vendor/uuid/README.md
vendored
2
vendor/uuid/README.md
vendored
|
@ -1,4 +1,4 @@
|
|||
## uuid v7.0.0-beta.0
|
||||
## uuid v8.1.0
|
||||
|
||||
Following files are copied from npm (node_modules):
|
||||
|
||||
|
|
2
vendor/uuid/uuid.min.js
vendored
2
vendor/uuid/uuid.min.js
vendored
|
@ -1 +1 @@
|
|||
!function(o,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(o=o||self).uuidv4=e()}(this,(function(){"use strict";var o="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof window.msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto),e=new Uint8Array(16);function r(){if(!o)throw new Error("uuid: This browser does not seem to support crypto.getRandomValues(). If you need to support this browser, please provide a custom random number generator through options.rng.");return o(e)}for(var n=[],t=0;t<256;++t)n[t]=(t+256).toString(16).substr(1);return function(o,e,t){var u=e&&t||0;"string"==typeof o&&(e="binary"===o?new Array(16):null,o=null);var i=(o=o||{}).random||(o.rng||r)();if(i[6]=15&i[6]|64,i[8]=63&i[8]|128,e)for(var s=0;s<16;++s)e[u+s]=i[s];return e||function(o,e){var r=e||0,t=n;return[t[o[r++]],t[o[r++]],t[o[r++]],t[o[r++]],"-",t[o[r++]],t[o[r++]],"-",t[o[r++]],t[o[r++]],"-",t[o[r++]],t[o[r++]],"-",t[o[r++]],t[o[r++]],t[o[r++]],t[o[r++]],t[o[r++]],t[o[r++]]].join("")}(i)}}));
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).uuidv4=e()}(this,(function(){"use strict";var t="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto),e=new Uint8Array(16);function n(){if(!t)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return t(e)}for(var o=[],r=0;r<256;++r)o.push((r+256).toString(16).substr(1));return function(t,e,r){"string"==typeof t&&(e="binary"===t?new Uint8Array(16):null,t=null);var u=(t=t||{}).random||(t.rng||n)();if(u[6]=15&u[6]|64,u[8]=63&u[8]|128,e){for(var i=r||0,d=0;d<16;++d)e[i+d]=u[d];return e}return function(t,e){var n=e||0,r=o;return(r[t[n+0]]+r[t[n+1]]+r[t[n+2]]+r[t[n+3]]+"-"+r[t[n+4]]+r[t[n+5]]+"-"+r[t[n+6]]+r[t[n+7]]+"-"+r[t[n+8]]+r[t[n+9]]+"-"+r[t[n+10]]+r[t[n+11]]+r[t[n+12]]+r[t[n+13]]+r[t[n+14]]+r[t[n+15]]).toLowerCase()}(u)}}));
|
Loading…
Reference in New Issue
Block a user