Merge pull request #150 from Mottie/stylelint
Include both CSSLint and stylelint
This commit is contained in:
commit
da565a5fa5
|
@ -27,9 +27,9 @@
|
|||
"message": "Изнасяне",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "Проблеми",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Цвят на фона",
|
||||
|
@ -664,9 +664,14 @@
|
|||
"message": "Прозорец за настройките",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "Проблеми, намерени от <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> при следните правила:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "Проблеми, намерени от $link$ при следните правила:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "Значка на иконката на лентата",
|
||||
|
@ -764,4 +769,4 @@
|
|||
"message": "Пресъздайте стила на Мрежата със Стайлус, разширението за стилове. То ви позволява лесно да инсталиране теми за много сайтове.",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
"message": "Exportovat",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "Problémy",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Barva pozadí",
|
||||
|
@ -652,9 +652,14 @@
|
|||
"message": "Možnosti rozhraní",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "Problémy nalezené aplikací <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> s těmito povolenými pravidly:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "Problémy nalezené aplikací $link$ s těmito povolenými pravidly:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "Ikona tlačítka na panelu",
|
||||
|
@ -752,4 +757,4 @@
|
|||
"message": "Změňte vzhled webů pomocí správce uživatelských stylů. Stylus umožňuje snadnou instalaci vzhledů a modifikací pro spoustu webů.",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
"message": "Exportieren",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "Probleme",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Hintergrundfarbe",
|
||||
|
@ -632,9 +632,14 @@
|
|||
"message": "Optionen",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "Die von <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> gefunden Fehler haben die folgenden Einstellungen:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "Die von $link$ gefunden Fehler haben die folgenden Einstellungen:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "Badge auf dem Toolbar-Icon",
|
||||
|
@ -728,4 +733,4 @@
|
|||
"message": "Gestalte das Web neu mit Stylus, dem Style Manager. Stylus ermöglicht dir ganz einfach Themes und Designs für viele populäre Websites zu installieren.",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,6 +107,26 @@
|
|||
"message": "Word wrap",
|
||||
"description": "Label for the checkbox controlling word wrap option for the style editor."
|
||||
},
|
||||
"cm_linter": {
|
||||
"message": "CSS Linter",
|
||||
"description": "Select the linter to check for CSS issues"
|
||||
},
|
||||
"cm_matchHighlight": {
|
||||
"message": "Highlight",
|
||||
"description": "Label for the drop-down list controlling the automatic highlighting of current word/selection occurrences in the style editor."
|
||||
},
|
||||
"cm_matchHighlightSelection": {
|
||||
"message": "Selection only",
|
||||
"description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of currently selected text"
|
||||
},
|
||||
"cm_matchHighlightToken": {
|
||||
"message": "Token under cursor",
|
||||
"description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of of the word/token under cursor even if nothing is selected"
|
||||
},
|
||||
"cm_resizeGripHint": {
|
||||
"message": "Double-click to maximize/restore the height",
|
||||
"description": "Tooltip for the resize grip in style editor"
|
||||
},
|
||||
"cm_smartIndent": {
|
||||
"message": "Use smart indentation",
|
||||
"description": "Label for the checkbox controlling smart indentation option for the style editor."
|
||||
|
@ -119,22 +139,6 @@
|
|||
"message": "Theme",
|
||||
"description": "Label for the style editor's CSS theme."
|
||||
},
|
||||
"cm_matchHighlight": {
|
||||
"message": "Highlight",
|
||||
"description": "Label for the drop-down list controlling the automatic highlighting of current word/selection occurrences in the style editor."
|
||||
},
|
||||
"cm_matchHighlightToken": {
|
||||
"message": "Token under cursor",
|
||||
"description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of of the word/token under cursor even if nothing is selected"
|
||||
},
|
||||
"cm_matchHighlightSelection": {
|
||||
"message": "Selection only",
|
||||
"description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of currently selected text"
|
||||
},
|
||||
"cm_resizeGripHint": {
|
||||
"message": "Double-click to maximize/restore the height",
|
||||
"description": "Tooltip for the resize grip in style editor"
|
||||
},
|
||||
"dysfunctional": {
|
||||
"message": "Stylus cannot function because Firefox is either in private mode or is applying its website cookies policy to IndexedDB storage used by Stylus, which erroneously marks the secure moz-extension:// origin as insecure even though WebExtensions aren't websites and Stylus doesn't use cookies.\n\n1. Open Firefox options\n2. Go to 'Privacy & Security'\n3. Set 'History' mode to 'Use custom settings'\n4. Click 'Exceptions'\n5. Paste our manifest URL and click 'Allow'\n6. Click 'Save settings'\n7. Uncheck 'Always use private browsing mode'\n\nThe actual manifest URL is shown below.\nYou can also find it on about:debugging page.",
|
||||
"description": "Displayed in Firefox when its settings make Stylus dysfunctional"
|
||||
|
@ -151,6 +155,14 @@
|
|||
"message": "History",
|
||||
"description": "Used in various places to show a history log of something"
|
||||
},
|
||||
"genericResetLabel": {
|
||||
"message": "Reset",
|
||||
"description": "Used in various parts of UI to indicate that something may be reset to its original state"
|
||||
},
|
||||
"genericSavedMessage": {
|
||||
"message": "Saved",
|
||||
"description": "Used in various parts of the UI to indicate that something was saved"
|
||||
},
|
||||
"confirmNo": {
|
||||
"message": "No",
|
||||
"description": "'No' button in a confirm dialog"
|
||||
|
@ -337,13 +349,51 @@
|
|||
"message": "Install update",
|
||||
"description": "Label for the button to install an update for a single style"
|
||||
},
|
||||
"issues": {
|
||||
"message": "Issues",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"linterConfigPopupTitle": {
|
||||
"message": "Set $linter$ rules configuration",
|
||||
"description": "Stylelint or CSSLint popup header",
|
||||
"placeholders": {
|
||||
"linter": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "The issues found by <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> with these rules enabled:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterConfigTooltip": {
|
||||
"message": "Click to configure this linter",
|
||||
"description": "Icon tooltip to indicate that it opens a popup with the selected linter configuration"
|
||||
},
|
||||
"linterCSSLintSettings": {
|
||||
"message": "(Set rule as: 0 = disabled; 1 = warning; 2 = error)",
|
||||
"description": "CSSLint rule config values"
|
||||
},
|
||||
"linterInvalidConfigError": {
|
||||
"message": "Not saved due to these invalid configuration settings:",
|
||||
"description": "Invalid linter config will show a message followed by a list of invalid entries"
|
||||
},
|
||||
"linterIssues": {
|
||||
"message": "Issues",
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"linterIssuesHelp": {
|
||||
"message": "These issues were found by $link$:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"linterJSONError": {
|
||||
"message": "Invalid JSON format",
|
||||
"description": "Setting linter config with invalid JSON"
|
||||
},
|
||||
"linterResetMessage": {
|
||||
"message": "To undo accidental reset, press Ctrl-Z (or Cmd-Z) in the text box",
|
||||
"description": "Reset button tooltip to inform user on how to undo an accidental reset"
|
||||
},
|
||||
"linterRulesLink": {
|
||||
"message": "See a full list of rules",
|
||||
"description": "Stylelint or CSSLint rules label added immediately before a link"
|
||||
},
|
||||
"manageFilters": {
|
||||
"message": "Filters",
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
"message": "Exportar",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "Problemas",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Color de fondo",
|
||||
|
@ -656,9 +656,14 @@
|
|||
"message": "Interfaz de opciones",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "Problemas encontrados por <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> con estas reglas aplicadas:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "Problemas encontrados por $link$ con estas reglas aplicadas:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "Distintivo en el icono de barra de herramientas",
|
||||
|
@ -752,4 +757,4 @@
|
|||
"message": "Rediseñe la web con Stylus, un administrador de estilos de usuario. Stylus le permite instalar fácilmente temas y coberturas para muchos sitios populares.",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
"message": "Ekspordi",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "Vead",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Taustavärv",
|
||||
|
@ -652,9 +652,14 @@
|
|||
"message": "Valikute liides",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "<a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> poolt leitud vead nende lubatud reeglitega:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "$link$ poolt leitud vead nende lubatud reeglitega:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "Number tööriistaribaikoonil",
|
||||
|
@ -752,4 +757,4 @@
|
|||
"message": "Disaini veeb ümber Stylus'ega - kasutajastiilide haldur. Stylus võimaldab sul lihtsalt installida teemasid ja välimusi mitmetele populaarsetele saitidele.",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
"message": "エクスポート",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "問題点",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "背景色",
|
||||
|
@ -648,9 +648,14 @@
|
|||
"message": "オプション UI",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "これらのルールを有効にして <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> で見つかった問題:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "これらのルールを有効にして $link$ で見つかった問題:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "ツールバーアイコンのバッジ",
|
||||
|
@ -748,4 +753,4 @@
|
|||
"message": "Stylus はユーザー スタイルを管理するツールで、ウェブのスタイルを変更することができます。Stylus を利用すると、さまざまなサイトに対応したテーマやスキンを簡単にインストールできます。",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"message": "Exporteren",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "Problemen",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"cm_tabSize": {
|
||||
"message": "Tabgrootte",
|
||||
|
@ -344,9 +344,14 @@
|
|||
"message": "Controleer alle stijlen op updates",
|
||||
"description": "Label for the button to check all styles for updates"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "De door CSSLint gevonden problemen, <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a>, met deze ingeschakelde regels:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "De door stylelint gevonden problemen, $link$, met deze ingeschakelde regels:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"confirmNo": {
|
||||
"message": "Nee",
|
||||
|
@ -396,4 +401,4 @@
|
|||
"message": "Voorzie het web van een ander uiterlijk met Stylus, een gebruikersstijlbeheerder. Stylus stelt u in staat om eenvoudig thema's en stijlen te installeren voor vele populaire websites.",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
"message": "Eksportuj",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "Problemy",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Kolor tła",
|
||||
|
@ -656,9 +656,14 @@
|
|||
"message": "Opcje interfejsu",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "Problemy znalezione przez <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> z tymi włączonymi regułami:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "Problemy znalezione przez $link$ z tymi włączonymi regułami:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "Emblemat na ikonie paska narzędzi",
|
||||
|
@ -756,4 +761,4 @@
|
|||
"message": "Przeprojektuj sieć za pomocą Stylusa - menedżera stylów użytkownika. Stylus umożliwia łatwe instalowanie motywów i skórek dla wielu popularnych stron.",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
"message": "Экспорт",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "Проблемы",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "Цвет фона",
|
||||
|
@ -656,9 +656,14 @@
|
|||
"message": "Настройки",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "Проблемы и предупреждения по версии <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> с данными включенными правилами:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "Проблемы и предупреждения по версии $link$ с данными включенными правилами:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "Бейдж на пиктограмме в тулбаре",
|
||||
|
@ -756,4 +761,4 @@
|
|||
"message": "Настраивайте стили веб-сайтов с помощью менеджера стилей Stylus. Он позволяет легко установить темы и изменить внешний вид сайтов Google, Facebook, YouTube, Orkut и множества других веб-страниц.",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"message": "Извези",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "Проблеми",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"cm_tabSize": {
|
||||
"message": "Величина картице",
|
||||
|
@ -356,9 +356,14 @@
|
|||
"message": "Проверите ажурирања за све стилове",
|
||||
"description": "Label for the button to check all styles for updates"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "Проблем пронађен од стране <a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> са овим омогућеним правилима:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "Проблем пронађен од стране $link$ са овим омогућеним правилима:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"confirmNo": {
|
||||
"message": "Не",
|
||||
|
@ -408,4 +413,4 @@
|
|||
"message": "Измените стил интернет мреже управљачем корисничких стилова. Stylus вам омогућава да лако инсталирате теме и скинове за многе популарне сајтове.",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
"message": "导出",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "问题",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "背景颜色",
|
||||
|
@ -656,9 +656,14 @@
|
|||
"message": "设置用户界面",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "<a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a> 在已启用的这些规则中找到问题:",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "$link$ 在已启用的这些规则中找到问题:",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "样式计数器",
|
||||
|
@ -756,4 +761,4 @@
|
|||
"message": "Stylus 是一个调整网页外观的用户样式管理器。它可让您轻松地为许多热门网站网站安装主题和皮肤。",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
"message": "導出",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
},
|
||||
"issues": {
|
||||
"linterIssues": {
|
||||
"message": "問題",
|
||||
"description": "Label for the CSSLint issues block on the style edit page"
|
||||
"description": "Label for the CSS linter issues block on the style edit page"
|
||||
},
|
||||
"optionsBadgeNormal": {
|
||||
"message": "背景顏色",
|
||||
|
@ -660,9 +660,14 @@
|
|||
"message": "選項介面",
|
||||
"description": "Go to Options UI"
|
||||
},
|
||||
"issuesHelp": {
|
||||
"message": "由<a href='https://github.com/CSSLint/csslint' target='_blank'>CSSLint</a>發現啟用這些規則會產生衝突",
|
||||
"description": "Help popup message for the CSSLint issues block on the style edit page"
|
||||
"linterIssuesHelp": {
|
||||
"message": "由$link$發現啟用這些規則會產生衝突",
|
||||
"description": "Help popup message for the selected CSS linter issues block on the style edit page",
|
||||
"placeholders": {
|
||||
"link": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsCustomizeBadge": {
|
||||
"message": "在工具列圖示上的徽章",
|
||||
|
@ -760,4 +765,4 @@
|
|||
"message": "用Stylus(一個用戶樣式管理器)重塑網頁。 Stylus 讓你能為诸多主流網站輕鬆的安裝主題和皮膚。",
|
||||
"description": "Extension description"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* global LZString */
|
||||
'use strict';
|
||||
|
||||
const RX_NAMESPACE = new RegExp([/[\s\r\n]*/,
|
||||
|
@ -41,6 +42,26 @@ var chromeLocal = {
|
|||
},
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var chromeSync = {
|
||||
get(options) {
|
||||
return new Promise(resolve => {
|
||||
chrome.storage.sync.get(options, data => resolve(data));
|
||||
});
|
||||
},
|
||||
set(data) {
|
||||
return new Promise(resolve => {
|
||||
chrome.storage.sync.set(data, () => resolve(data));
|
||||
});
|
||||
},
|
||||
getValue(key) {
|
||||
return chromeSync.get(key).then(data => tryJSONparse(LZString.decompressFromUTF16(data[key])));
|
||||
},
|
||||
setValue(key, value) {
|
||||
return chromeSync.set({[key]: LZString.compressToUTF16(JSON.stringify(value))});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function dbExec(method, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
23
edit.html
23
edit.html
|
@ -9,6 +9,7 @@
|
|||
<script src="content/apply.js"></script>
|
||||
<link rel="stylesheet" href="edit/edit.css">
|
||||
<script src="edit/edit.js"></script>
|
||||
<script src="edit/lint.js"></script>
|
||||
|
||||
<script src="vendor/codemirror/lib/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="vendor/codemirror/lib/codemirror.css">
|
||||
|
@ -33,11 +34,6 @@
|
|||
|
||||
<script src="vendor/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="vendor/codemirror/addon/lint/lint.css" />
|
||||
<script src="vendor/csslint/csslint-worker.js"></script>
|
||||
<script src="vendor/codemirror/addon/lint/lint.js"></script>
|
||||
<script src="vendor-overwrites/codemirror/addon/lint/css-lint.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="vendor/codemirror/addon/hint/show-hint.css" />
|
||||
<script src="vendor/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script src="vendor/codemirror/addon/hint/css-hint.js"></script>
|
||||
|
@ -186,8 +182,20 @@
|
|||
<option i18n-text="genericDisabledLabel" value="">
|
||||
</select>
|
||||
</div>
|
||||
<div class="option aligned">
|
||||
<label id="linter-label" for="editor.linter" i18n-text="cm_linter"></label>
|
||||
<select id="editor.linter">
|
||||
<option value="csslint" selected>CSSLint</option>
|
||||
<option value="stylelint">Stylelint</option>
|
||||
<option value="null" i18n-text="genericDisabledLabel"></option>
|
||||
</select>
|
||||
<span class="linter-settings" i18n-title="linterConfigTooltip">
|
||||
<svg id="linter-settings" class="svg-icon settings">
|
||||
<use xlink:href="#svg-icon-settings"/>
|
||||
</svg>
|
||||
</span>
|
||||
</section>
|
||||
<section id="lint"><h2 i18n-text="issues">: <span id="issue-count"></span><svg id="lint-help" class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg></h2><div></div></section>
|
||||
<section id="lint"><h2 i18n-text="linterIssues">: <span id="issue-count"></span><svg id="lint-help" class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg></h2><div></div></section>
|
||||
</div>
|
||||
<section id="sections">
|
||||
<h2><span id="sections-heading" i18n-text="styleSectionsTitle"></span><svg id="sections-help" class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg></h2>
|
||||
|
@ -207,6 +215,9 @@
|
|||
<symbol id="svg-icon-close" height="16" width="12" viewBox="0 0 12 16">
|
||||
<path fill-rule="evenodd" d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"></path>
|
||||
</symbol>
|
||||
<symbol id="svg-icon-settings" height="12" width="12" viewBox="0 0 16 16">
|
||||
<path d="M16 9.45V6.52l-1.8-.3c-.14-.5-.34-.95-.56-1.35L14.7 3.4l-2.07-2.1-1.5 1.03c-.43-.24-.9-.43-1.37-.56L9.46 0H6.54l-.3 1.8c-.5.13-.94.33-1.36.55L3.4 1.32 1.3 3.4l1.07 1.45c-.24.45-.44.92-.57 1.42L0 6.53v2.95l1.8.3c.14.52.33.95.57 1.37l-1.07 1.5 2.06 2.08 1.5-1.07c.44.24.9.45 1.4.57l.3 1.77H9.5l.32-1.8c.47-.13.95-.32 1.34-.56l1.5 1.06 2.07-2.05-1.03-1.5c.24-.45.44-.9.56-1.36L16 9.44v-.02zm-8 1.6C6.3 11.05 4.93 9.7 4.93 8S6.33 4.9 8 4.9s3.06 1.4 3.06 3.1S9.7 11.04 8 11.04z"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
</body>
|
||||
|
|
49
edit/csslint-config.js
Normal file
49
edit/csslint-config.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* CSSLint Config values
|
||||
* 0 = disabled; 1 = warning; 2 = error
|
||||
*/
|
||||
window.csslintDefaultConfig = {
|
||||
// Default warnings
|
||||
'display-property-grouping': 1,
|
||||
'duplicate-properties': 1,
|
||||
'empty-rules': 1,
|
||||
'errors': 1,
|
||||
'known-properties': 1,
|
||||
|
||||
// Default disabled
|
||||
'adjoining-classes': 0,
|
||||
'box-model': 0,
|
||||
'box-sizing': 0,
|
||||
'bulletproof-font-face': 0,
|
||||
'compatible-vendor-prefixes': 0,
|
||||
'duplicate-background-images': 0,
|
||||
'fallback-colors': 0,
|
||||
'floats': 0,
|
||||
'font-faces': 0,
|
||||
'font-sizes': 0,
|
||||
'gradients': 0,
|
||||
'ids': 0,
|
||||
'import': 0,
|
||||
'import-ie-limit': 0,
|
||||
'important': 0,
|
||||
'order-alphabetical': 0,
|
||||
'outline-none': 0,
|
||||
'overqualified-elements': 0,
|
||||
'qualified-headings': 0,
|
||||
'regex-selectors': 0,
|
||||
'rules-count': 0,
|
||||
'selector-max': 0,
|
||||
'selector-max-approaching': 0,
|
||||
'selector-newline': 0,
|
||||
'shorthand': 0,
|
||||
'star-property-hack': 0,
|
||||
'text-indent': 0,
|
||||
'underscore-property-hack': 0,
|
||||
'unique-headings': 0,
|
||||
'universal-selector': 0,
|
||||
'unqualified-attributes': 0,
|
||||
'vendor-prefix': 0,
|
||||
'zero-units': 0
|
||||
};
|
|
@ -73,16 +73,19 @@ input[type="checkbox"] {
|
|||
h2 .svg-icon, label .svg-icon {
|
||||
margin-top: -1px;
|
||||
}
|
||||
.svg-icon.info {
|
||||
.svg-icon.info,
|
||||
.svg-icon.settings {
|
||||
width: 14px;
|
||||
height: 16px;
|
||||
}
|
||||
.svg-icon:hover,
|
||||
.svg-icon.info {
|
||||
.svg-icon.info,
|
||||
.svg-icon.settings {
|
||||
fill: #666;
|
||||
}
|
||||
.svg-icon,
|
||||
.svg-icon.info:hover {
|
||||
.svg-icon.info:hover,
|
||||
.svg-icon.settings:hover {
|
||||
fill: #000;
|
||||
}
|
||||
#enabled {
|
||||
|
@ -361,11 +364,26 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar
|
|||
max-height: calc(100vh - 8rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
#help-popup .settings {
|
||||
min-width: 500px;
|
||||
min-height: 200px;
|
||||
max-width: 48vw;
|
||||
}
|
||||
#help-popup .dismiss {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: .5em;
|
||||
}
|
||||
#help-popup .saved-message {
|
||||
display: none;
|
||||
color: #090;
|
||||
margin-left: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
#help-popup .saved-message.show,
|
||||
#options .linter-settings {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.keymap-list {
|
||||
font-size: 85%;
|
||||
|
@ -397,6 +415,12 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar
|
|||
pointer-events: all;
|
||||
opacity: 1.0;
|
||||
}
|
||||
#help-popup .rules {
|
||||
padding: 0 15px;
|
||||
}
|
||||
#help-popup button {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
/************ lint ************/
|
||||
#lint {
|
||||
|
@ -428,7 +452,6 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar
|
|||
#lint td[role="severity"] {
|
||||
font-size: 0;
|
||||
width: 16px;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
#lint td[role="line"], #lint td[role="sep"] {
|
||||
text-align: right;
|
||||
|
@ -441,6 +464,9 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar
|
|||
#lint td[role="message"] {
|
||||
text-align: left;
|
||||
}
|
||||
#message-box.center.lint-config #message-box-contents {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/************ CSS beautifier ************/
|
||||
.beautify-options {
|
||||
|
@ -543,7 +569,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar
|
|||
margin-bottom: 0;
|
||||
}
|
||||
#lint > div {
|
||||
max-height: 0;
|
||||
max-height: 20vh;
|
||||
}
|
||||
#lint.collapsed > div {
|
||||
display: none;
|
||||
|
@ -552,6 +578,12 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar
|
|||
margin-top: 1em;
|
||||
max-height: 30vh;
|
||||
}
|
||||
#lint table {
|
||||
width: 100%;
|
||||
}
|
||||
#lint td[role="message"] {
|
||||
max-width: none;
|
||||
}
|
||||
#sections {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
|
435
edit/edit.js
435
edit/edit.js
|
@ -1,12 +1,17 @@
|
|||
/* eslint brace-style: 0, operator-linebreak: 0 */
|
||||
/* global CodeMirror exports parserlib CSSLint */
|
||||
/* global CodeMirror parserlib */
|
||||
/* global exports css_beautify onDOMscripted */
|
||||
/* global CSSLint initLint getLinterConfigForCodeMirror updateLintReport renderLintReport updateLinter */
|
||||
'use strict';
|
||||
|
||||
let styleId = null;
|
||||
let dirty = {}; // only the actually dirty items here
|
||||
const editors = []; // array of all CodeMirror instances
|
||||
// only the actually dirty items here
|
||||
let dirty = {};
|
||||
// array of all CodeMirror instances
|
||||
const editors = [];
|
||||
let saveSizeOnClose;
|
||||
let useHistoryBack; // use browser history back when 'back to manage' is clicked
|
||||
// use browser history back when 'back to manage' is clicked
|
||||
let useHistoryBack;
|
||||
|
||||
// direct & reverse mapping of @-moz-document keywords and internal property names
|
||||
const propertyToCss = {urls: 'url', urlPrefixes: 'url-prefix', domains: 'domain', regexps: 'regexp'};
|
||||
|
@ -32,7 +37,8 @@ Element.prototype.closest = Element.prototype.closest || function (selector) {
|
|||
};
|
||||
|
||||
// eslint-disable-next-line no-extend-native
|
||||
Array.prototype.rotate = function (amount) { // negative amount == rotate left
|
||||
Array.prototype.rotate = function (amount) {
|
||||
// negative amount == rotate left
|
||||
const r = this.slice(-amount, this.length);
|
||||
Array.prototype.push.apply(r, this.slice(0, this.length - r.length));
|
||||
return r;
|
||||
|
@ -43,7 +49,7 @@ Object.defineProperty(Array.prototype, 'last', {get: function () { return this[t
|
|||
|
||||
// preload the theme so that CodeMirror can calculate its metrics in DOMContentLoaded->setupLivePrefs()
|
||||
new MutationObserver((mutations, observer) => {
|
||||
const themeElement = document.getElementById('cm-theme');
|
||||
const themeElement = $('#cm-theme');
|
||||
if (themeElement) {
|
||||
themeElement.href = prefs.get('editor.theme') === 'default' ? ''
|
||||
: 'vendor/codemirror/theme/' + prefs.get('editor.theme') + '.css';
|
||||
|
@ -91,7 +97,8 @@ function onChange(event) {
|
|||
} else {
|
||||
// the manually added section's applies-to is dirty only when the value is non-empty
|
||||
setCleanItem(node, node.localName !== 'input' || !node.value.trim());
|
||||
delete node.savedValue; // only valid when actually saved
|
||||
// only valid when actually saved
|
||||
delete node.savedValue;
|
||||
}
|
||||
updateTitle();
|
||||
}
|
||||
|
@ -124,7 +131,7 @@ function setCleanItem(node, isClean) {
|
|||
function isCleanGlobal() {
|
||||
const clean = Object.keys(dirty).length === 0;
|
||||
setDirtyClass(document.body, !clean);
|
||||
// let saveBtn = document.getElementById('save-button')
|
||||
// let saveBtn = $('#save-button')
|
||||
// if (clean){
|
||||
// //saveBtn.removeAttribute('disabled');
|
||||
// }else{
|
||||
|
@ -134,12 +141,13 @@ function isCleanGlobal() {
|
|||
}
|
||||
|
||||
function setCleanGlobal() {
|
||||
document.querySelectorAll('#header, #sections > div').forEach(setCleanSection);
|
||||
dirty = {}; // forget the dirty applies-to ids from a deleted section after the style was saved
|
||||
$$('#header, #sections > div').forEach(setCleanSection);
|
||||
// forget the dirty applies-to ids from a deleted section after the style was saved
|
||||
dirty = {};
|
||||
}
|
||||
|
||||
function setCleanSection(section) {
|
||||
section.querySelectorAll('.style-contributor').forEach(node => { setCleanItem(node, true); });
|
||||
$$('.style-contributor', section).forEach(node => { setCleanItem(node, true); });
|
||||
|
||||
// #header section has no codemirror
|
||||
const cm = section.CodeMirror;
|
||||
|
@ -152,6 +160,9 @@ function setCleanSection(section) {
|
|||
function initCodeMirror() {
|
||||
const CM = CodeMirror;
|
||||
const isWindowsOS = navigator.appVersion.indexOf('Windows') > 0;
|
||||
// lint.js is not loaded initially
|
||||
const hasLinter = typeof getLinterConfigForCodeMirror !== 'undefined' ?
|
||||
getLinterConfigForCodeMirror(prefs.get('editor.linter')) : false;
|
||||
|
||||
// CodeMirror miserably fails on keyMap='' so let's ensure it's not
|
||||
if (!prefs.get('editor.keyMap')) {
|
||||
|
@ -168,12 +179,13 @@ function initCodeMirror() {
|
|||
matchBrackets: true,
|
||||
highlightSelectionMatches: {showToken: /[#.\-\w]/, annotateScrollbar: true},
|
||||
hintOptions: {},
|
||||
lint: {getAnnotations: CodeMirror.lint.css, delay: prefs.get('editor.lintDelay')},
|
||||
lint: hasLinter,
|
||||
lintReportDelay: prefs.get('editor.lintReportDelay'),
|
||||
styleActiveLine: true,
|
||||
theme: 'default',
|
||||
keyMap: prefs.get('editor.keyMap'),
|
||||
extraKeys: { // independent of current keyMap
|
||||
extraKeys: {
|
||||
// independent of current keyMap
|
||||
'Alt-Enter': 'toggleStyle',
|
||||
'Alt-PageDown': 'nextEditor',
|
||||
'Alt-PageUp': 'prevEditor'
|
||||
|
@ -203,9 +215,12 @@ function initCodeMirror() {
|
|||
CM.keyMap.macDefault['Cmd-J'] = 'jumpToLine';
|
||||
}
|
||||
if (!extraKeysCommands.autocomplete) {
|
||||
CM.keyMap.pcDefault['Ctrl-Space'] = 'autocomplete'; // will be used by 'sublime' on PC via fallthrough
|
||||
CM.keyMap.macDefault['Alt-Space'] = 'autocomplete'; // OSX uses Ctrl-Space and Cmd-Space for something else
|
||||
CM.keyMap.emacsy['Alt-/'] = 'autocomplete'; // copied from 'emacs' keymap
|
||||
// will be used by 'sublime' on PC via fallthrough
|
||||
CM.keyMap.pcDefault['Ctrl-Space'] = 'autocomplete';
|
||||
// OSX uses Ctrl-Space and Cmd-Space for something else
|
||||
CM.keyMap.macDefault['Alt-Space'] = 'autocomplete';
|
||||
// copied from 'emacs' keymap
|
||||
CM.keyMap.emacsy['Alt-/'] = 'autocomplete';
|
||||
// 'vim' and 'emacs' define their own autocomplete hotkeys
|
||||
}
|
||||
if (!extraKeysCommands.blockComment) {
|
||||
|
@ -223,8 +238,10 @@ function initCodeMirror() {
|
|||
|
||||
// try to remap non-interceptable Ctrl-(Shift-)N/T/W hotkeys
|
||||
['N', 'T', 'W'].forEach(char => {
|
||||
[{from: 'Ctrl-', to: ['Alt-', 'Ctrl-Alt-']},
|
||||
{from: 'Shift-Ctrl-', to: ['Ctrl-Alt-', 'Shift-Ctrl-Alt-']} // Note: modifier order in CM is S-C-A
|
||||
[
|
||||
{from: 'Ctrl-', to: ['Alt-', 'Ctrl-Alt-']},
|
||||
// Note: modifier order in CM is S-C-A
|
||||
{from: 'Shift-Ctrl-', to: ['Ctrl-Alt-', 'Shift-Ctrl-Alt-']}
|
||||
].forEach(remap => {
|
||||
const oldKey = remap.from + char;
|
||||
Object.keys(CM.keyMap).forEach(keyMapName => {
|
||||
|
@ -267,7 +284,8 @@ function initCodeMirror() {
|
|||
}
|
||||
parent.appendChild(fragment);
|
||||
}
|
||||
const themeControl = document.getElementById('editor.theme');
|
||||
// no need to escape the period in the id
|
||||
const themeControl = $('#editor.theme');
|
||||
const themeList = localStorage.codeMirrorThemes;
|
||||
if (themeList) {
|
||||
optionsFromArray(themeControl, themeList.split(/\s+/));
|
||||
|
@ -282,7 +300,7 @@ function initCodeMirror() {
|
|||
});
|
||||
}
|
||||
optionsFromArray($('#editor.keyMap'), Object.keys(CM.keyMap).sort());
|
||||
document.getElementById('options').addEventListener('change', acmeEventListener, false);
|
||||
$('#options').addEventListener('change', acmeEventListener, false);
|
||||
setupLivePrefs();
|
||||
|
||||
hotkeyRerouter.setState(true);
|
||||
|
@ -302,7 +320,7 @@ function acmeEventListener(event) {
|
|||
CodeMirror.setOption('indentUnit', Number(value));
|
||||
break;
|
||||
case 'theme': {
|
||||
const themeLink = document.getElementById('cm-theme');
|
||||
const themeLink = $('#cm-theme');
|
||||
// use non-localized 'default' internally
|
||||
if (!value || value === 'default' || value === t('defaultTheme')) {
|
||||
value = 'default';
|
||||
|
@ -314,7 +332,8 @@ function acmeEventListener(event) {
|
|||
break;
|
||||
}
|
||||
const url = chrome.runtime.getURL('vendor/codemirror/theme/' + value + '.css');
|
||||
if (themeLink.href === url) { // preloaded in initCodeMirror()
|
||||
if (themeLink.href === url) {
|
||||
// preloaded in initCodeMirror()
|
||||
break;
|
||||
}
|
||||
// avoid flicker: wait for the second stylesheet to load, then apply the theme
|
||||
|
@ -348,6 +367,10 @@ function acmeEventListener(event) {
|
|||
default:
|
||||
value = null;
|
||||
}
|
||||
break;
|
||||
case 'linter':
|
||||
updateLinter(value);
|
||||
break;
|
||||
}
|
||||
CodeMirror.setOption(option, value);
|
||||
}
|
||||
|
@ -391,8 +414,10 @@ function setupCodeMirror(textarea, index) {
|
|||
}
|
||||
lastClickTime = Date.now();
|
||||
const minHeight = cm.defaultTextHeight() +
|
||||
cm.display.lineDiv.offsetParent.offsetTop + /* .CodeMirror-lines padding */
|
||||
wrapper.offsetHeight - wrapper.clientHeight; /* borders */
|
||||
/* .CodeMirror-lines padding */
|
||||
cm.display.lineDiv.offsetParent.offsetTop +
|
||||
/* borders */
|
||||
wrapper.offsetHeight - wrapper.clientHeight;
|
||||
wrapper.style.pointerEvents = 'none';
|
||||
document.body.style.cursor = 's-resize';
|
||||
function resize(e) {
|
||||
|
@ -419,7 +444,7 @@ function indicateCodeChange(cm) {
|
|||
const section = cm.getSection();
|
||||
setCleanItem(section, cm.isClean(section.savedValue));
|
||||
updateTitle();
|
||||
updateLintReport(cm);
|
||||
updateLintReportIfEnabled(cm);
|
||||
}
|
||||
|
||||
function getSectionForChild(e) {
|
||||
|
@ -427,13 +452,13 @@ function getSectionForChild(e) {
|
|||
}
|
||||
|
||||
function getSections() {
|
||||
return document.querySelectorAll('#sections > div');
|
||||
return $$('#sections > div');
|
||||
}
|
||||
|
||||
// remind Chrome to repaint a previously invisible editor box by toggling any element's transform
|
||||
// this bug is present in some versions of Chrome (v37-40 or something)
|
||||
document.addEventListener('scroll', () => {
|
||||
const style = document.getElementById('name').style;
|
||||
const style = $('#name').style;
|
||||
style.webkitTransform = style.webkitTransform ? '' : 'scale(1)';
|
||||
});
|
||||
|
||||
|
@ -546,12 +571,12 @@ window.onbeforeunload = () => {
|
|||
if (isCleanGlobal()) {
|
||||
return;
|
||||
}
|
||||
updateLintReport(null, 0);
|
||||
updateLintReportIfEnabled(null, 0);
|
||||
return confirm(t('styleChangesNotSaved'));
|
||||
};
|
||||
|
||||
function addAppliesTo(list, name, value) {
|
||||
const showingEverything = list.querySelector('.applies-to-everything') !== null;
|
||||
const showingEverything = $('.applies-to-everything', list) !== null;
|
||||
// blow away 'Everything' if it's there
|
||||
if (showingEverything) {
|
||||
list.removeChild(list.firstChild);
|
||||
|
@ -559,19 +584,19 @@ function addAppliesTo(list, name, value) {
|
|||
let e;
|
||||
if (name && value) {
|
||||
e = template.appliesTo.cloneNode(true);
|
||||
e.querySelector('[name=applies-type]').value = name;
|
||||
e.querySelector('[name=applies-value]').value = value;
|
||||
e.querySelector('.remove-applies-to').addEventListener('click', removeAppliesTo, false);
|
||||
$('[name=applies-type]', e).value = name;
|
||||
$('[name=applies-value]', e).value = value;
|
||||
$('.remove-applies-to', e).addEventListener('click', removeAppliesTo, false);
|
||||
} else if (showingEverything || list.hasChildNodes()) {
|
||||
e = template.appliesTo.cloneNode(true);
|
||||
if (list.hasChildNodes()) {
|
||||
e.querySelector('[name=applies-type]').value = list.querySelector('li:last-child [name="applies-type"]').value;
|
||||
$('[name=applies-type]', e).value = $('li:last-child [name="applies-type"]', list).value;
|
||||
}
|
||||
e.querySelector('.remove-applies-to').addEventListener('click', removeAppliesTo, false);
|
||||
$('.remove-applies-to', e).addEventListener('click', removeAppliesTo, false);
|
||||
} else {
|
||||
e = template.appliesToEverything.cloneNode(true);
|
||||
}
|
||||
e.querySelector('.add-applies-to').addEventListener('click', function () {
|
||||
$('.add-applies-to', e).addEventListener('click', function () {
|
||||
addAppliesTo(this.parentNode.parentNode);
|
||||
}, false);
|
||||
list.appendChild(e);
|
||||
|
@ -579,13 +604,13 @@ function addAppliesTo(list, name, value) {
|
|||
|
||||
function addSection(event, section) {
|
||||
const div = template.section.cloneNode(true);
|
||||
div.querySelector('.applies-to-help').addEventListener('click', showAppliesToHelp, false);
|
||||
div.querySelector('.remove-section').addEventListener('click', removeSection, false);
|
||||
div.querySelector('.add-section').addEventListener('click', addSection, false);
|
||||
div.querySelector('.beautify-section').addEventListener('click', beautify);
|
||||
$('.applies-to-help', div).addEventListener('click', showAppliesToHelp, false);
|
||||
$('.remove-section', div).addEventListener('click', removeSection, false);
|
||||
$('.add-section', div).addEventListener('click', addSection, false);
|
||||
$('.beautify-section', div).addEventListener('click', beautify);
|
||||
|
||||
const codeElement = div.querySelector('.code');
|
||||
const appliesTo = div.querySelector('.applies-to-list');
|
||||
const codeElement = $('.code', div);
|
||||
const appliesTo = $('.applies-to-list', div);
|
||||
let appliesToAdded = false;
|
||||
|
||||
if (section) {
|
||||
|
@ -608,24 +633,25 @@ function addSection(event, section) {
|
|||
|
||||
toggleTestRegExpVisibility();
|
||||
appliesTo.addEventListener('change', toggleTestRegExpVisibility);
|
||||
div.querySelector('.test-regexp').onclick = showRegExpTester;
|
||||
$('.test-regexp', div).onclick = showRegExpTester;
|
||||
function toggleTestRegExpVisibility() {
|
||||
const show = [...appliesTo.children].some(item =>
|
||||
!item.matches('.applies-to-everything') &&
|
||||
item.querySelector('.applies-type').value === 'regexp' &&
|
||||
item.querySelector('.applies-value').value.trim());
|
||||
$('.applies-type', item).value === 'regexp' &&
|
||||
$('.applies-value', item).value.trim()
|
||||
);
|
||||
div.classList.toggle('has-regexp', show);
|
||||
appliesTo.oninput = appliesTo.oninput || show && (event => {
|
||||
if (
|
||||
event.target.matches('.applies-value') &&
|
||||
event.target.parentElement.querySelector('.applies-type').value === 'regexp'
|
||||
$('.applies-type', event.target.parentElement).value === 'regexp'
|
||||
) {
|
||||
showRegExpTester(null, div);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const sections = document.getElementById('sections');
|
||||
const sections = $('#sections');
|
||||
let cm;
|
||||
if (event) {
|
||||
const clickedSection = getSectionForChild(event.target);
|
||||
|
@ -639,7 +665,6 @@ function addSection(event, section) {
|
|||
sections.appendChild(div);
|
||||
cm = setupCodeMirror(codeElement);
|
||||
}
|
||||
|
||||
div.CodeMirror = cm;
|
||||
setCleanSection(div);
|
||||
return div;
|
||||
|
@ -663,7 +688,7 @@ function removeSection(event) {
|
|||
}
|
||||
|
||||
function removeAreaAndSetDirty(area) {
|
||||
const contributors = area.querySelectorAll('.style-contributor');
|
||||
const contributors = $$('.style-contributor', area);
|
||||
if (!contributors.length) {
|
||||
setCleanItem(area, false);
|
||||
}
|
||||
|
@ -707,9 +732,11 @@ function setupGlobalSearch() {
|
|||
const originalOpenDialog = CodeMirror.prototype.openDialog;
|
||||
const originalOpenConfirm = CodeMirror.prototype.openConfirm;
|
||||
|
||||
let curState; // cm.state.search for last used 'find'
|
||||
// cm.state.search for last used 'find'
|
||||
let curState;
|
||||
|
||||
function shouldIgnoreCase(query) { // treat all-lowercase non-regexp queries as case-insensitive
|
||||
function shouldIgnoreCase(query) {
|
||||
// treat all-lowercase non-regexp queries as case-insensitive
|
||||
return typeof query === 'string' && query === query.toLowerCase();
|
||||
}
|
||||
|
||||
|
@ -779,7 +806,8 @@ function setupGlobalSearch() {
|
|||
return;
|
||||
}
|
||||
let pos = activeCM.getCursor(reverse ? 'from' : 'to');
|
||||
activeCM.setSelection(activeCM.getCursor()); // clear the selection, don't move the cursor
|
||||
// clear the selection, don't move the cursor
|
||||
activeCM.setSelection(activeCM.getCursor());
|
||||
|
||||
const rxQuery = typeof state.query === 'object'
|
||||
? state.query : stringAsRegExp(state.query, shouldIgnoreCase(state.query) ? 'i' : '');
|
||||
|
@ -820,7 +848,7 @@ function setupGlobalSearch() {
|
|||
originalCommand[reverse ? 'findPrev' : 'findNext'](activeCM);
|
||||
|
||||
function searchAppliesTo(cm) {
|
||||
let inputs = [].slice.call(cm.getSection().querySelectorAll('.applies-value'));
|
||||
let inputs = $$('.applies-value', cm.getSection());
|
||||
if (reverse) {
|
||||
inputs = inputs.reverse();
|
||||
}
|
||||
|
@ -883,7 +911,7 @@ function setupGlobalSearch() {
|
|||
} else {
|
||||
doConfirm(cm);
|
||||
callback(replacement);
|
||||
if (!cm.getWrapperElement().querySelector('.CodeMirror-dialog')) {
|
||||
if (!$('.CodeMirror-dialog', cm.getWrapperElement())) {
|
||||
// no dialog == nothing found in the current CM, move to the next
|
||||
doReplace();
|
||||
}
|
||||
|
@ -907,7 +935,7 @@ function setupGlobalSearch() {
|
|||
const cmp = CodeMirror.cmpPos(cm.getCursor(), pos);
|
||||
wrapAround |= cmp <= 0;
|
||||
|
||||
const dlg = cm.getWrapperElement().querySelector('.CodeMirror-dialog');
|
||||
const dlg = $('.CodeMirror-dialog', cm.getWrapperElement());
|
||||
if (!dlg || cmp === 0 || wrapAround && CodeMirror.cmpPos(cm.getCursor(), origPos) >= 0) {
|
||||
if (dlg) {
|
||||
dlg.remove();
|
||||
|
@ -1000,14 +1028,14 @@ function autocompletePicked(cm) {
|
|||
|
||||
function refocusMinidialog(cm) {
|
||||
const section = cm.getSection();
|
||||
if (!section.querySelector('.CodeMirror-dialog')) {
|
||||
if (!$('.CodeMirror-dialog', section)) {
|
||||
return;
|
||||
}
|
||||
// close the currently opened minidialog
|
||||
cm.focus();
|
||||
// make sure to focus the input in newly opened minidialog
|
||||
setTimeout(() => {
|
||||
section.querySelector('.CodeMirror-dialog').focus();
|
||||
$('.CodeMirror-dialog', section).focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
|
@ -1037,7 +1065,8 @@ function getEditorInSight(nearbyElement) {
|
|||
return cm;
|
||||
|
||||
function offscreenDistance(cm) {
|
||||
const LINES_VISIBLE = 2; // closest editor should have at least # lines visible
|
||||
// closest editor should have at least # lines visible
|
||||
const LINES_VISIBLE = 2;
|
||||
const bounds = cm.getSection().getBoundingClientRect();
|
||||
if (bounds.top < 0) {
|
||||
return -bounds.top;
|
||||
|
@ -1049,145 +1078,11 @@ function getEditorInSight(nearbyElement) {
|
|||
}
|
||||
}
|
||||
|
||||
function updateLintReport(cm, delay) {
|
||||
if (delay === 0) {
|
||||
// immediately show pending csslint messages in onbeforeunload and save
|
||||
update(cm);
|
||||
return;
|
||||
}
|
||||
if (delay > 0) {
|
||||
setTimeout(cm => { cm.performLint(); update(cm); }, delay, cm);
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line no-var
|
||||
var state = cm.state.lint;
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
// user is editing right now: postpone updating the report for the new issues (default: 500ms lint + 4500ms)
|
||||
// or update it as soon as possible (default: 500ms lint + 100ms) in case an existing issue was just fixed
|
||||
clearTimeout(state.reportTimeout);
|
||||
state.reportTimeout = setTimeout(update, state.options.delay + 100, cm);
|
||||
state.postponeNewIssues = delay === undefined || delay === null;
|
||||
|
||||
function update(cm) {
|
||||
const scope = cm ? [cm] : editors;
|
||||
let changed = false;
|
||||
let fixedOldIssues = false;
|
||||
scope.forEach(cm => {
|
||||
const scopedState = cm.state.lint || {};
|
||||
const oldMarkers = scopedState.markedLast || {};
|
||||
const newMarkers = {};
|
||||
const html = !scopedState.marked || scopedState.marked.length === 0 ? '' : '<tbody>' +
|
||||
scopedState.marked.map(mark => {
|
||||
const info = mark.__annotation;
|
||||
const isActiveLine = info.from.line === cm.getCursor().line;
|
||||
const pos = isActiveLine ? 'cursor' : (info.from.line + ',' + info.from.ch);
|
||||
let message = escapeHtml(info.message.replace(/ at line \d.+$/, ''));
|
||||
if (message.length > 100) {
|
||||
message = message.substr(0, 100) + '...';
|
||||
}
|
||||
if (isActiveLine || oldMarkers[pos] === message) {
|
||||
delete oldMarkers[pos];
|
||||
}
|
||||
newMarkers[pos] = message;
|
||||
return '<tr class="' + info.severity + '">' +
|
||||
'<td role="severity" class="CodeMirror-lint-marker-' + info.severity + '">' +
|
||||
info.severity + '</td>' +
|
||||
'<td role="line">' + (info.from.line + 1) + '</td>' +
|
||||
'<td role="sep">:</td>' +
|
||||
'<td role="col">' + (info.from.ch + 1) + '</td>' +
|
||||
'<td role="message">' + message + '</td></tr>';
|
||||
}).join('') + '</tbody>';
|
||||
scopedState.markedLast = newMarkers;
|
||||
fixedOldIssues |= scopedState.reportDisplayed && Object.keys(oldMarkers).length > 0;
|
||||
if (scopedState.html !== html) {
|
||||
scopedState.html = html;
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
clearTimeout(state ? state.renderTimeout : undefined);
|
||||
if (!state || !state.postponeNewIssues || fixedOldIssues) {
|
||||
renderLintReport(true);
|
||||
} else {
|
||||
state.renderTimeout = setTimeout(() => {
|
||||
renderLintReport(true);
|
||||
}, CodeMirror.defaults.lintReportDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
function escapeHtml(html) {
|
||||
const chars = {'&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/'};
|
||||
return html.replace(/[&<>"'/]/g, char => chars[char]);
|
||||
}
|
||||
}
|
||||
|
||||
function renderLintReport(someBlockChanged) {
|
||||
const container = document.getElementById('lint');
|
||||
const content = container.children[1];
|
||||
const label = t('sectionCode');
|
||||
const newContent = content.cloneNode(false);
|
||||
let issueCount = 0;
|
||||
editors.forEach((cm, index) => {
|
||||
if (cm.state.lint && cm.state.lint.html) {
|
||||
const html = '<caption>' + label + ' ' + (index + 1) + '</caption>' + cm.state.lint.html;
|
||||
const newBlock = newContent.appendChild(tHTML(html, 'table'));
|
||||
|
||||
newBlock.cm = cm;
|
||||
issueCount += newBlock.rows.length;
|
||||
|
||||
const block = content.children[newContent.children.length - 1];
|
||||
const blockChanged = !block || cm !== block.cm || html !== block.innerHTML;
|
||||
someBlockChanged |= blockChanged;
|
||||
cm.state.lint.reportDisplayed = blockChanged;
|
||||
}
|
||||
});
|
||||
if (someBlockChanged || newContent.children.length !== content.children.length) {
|
||||
document.getElementById('issue-count').textContent = issueCount;
|
||||
container.replaceChild(newContent, content);
|
||||
container.style.display = newContent.children.length ? 'block' : 'none';
|
||||
resizeLintReport(null, newContent);
|
||||
}
|
||||
}
|
||||
|
||||
function resizeLintReport(event, content) {
|
||||
content = content || document.getElementById('lint').children[1];
|
||||
if (content.children.length) {
|
||||
const bounds = content.getBoundingClientRect();
|
||||
const newMaxHeight = bounds.bottom <= innerHeight ? '' : (innerHeight - bounds.top) + 'px';
|
||||
if (newMaxHeight !== content.style.maxHeight) {
|
||||
content.style.maxHeight = newMaxHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function gotoLintIssue(event) {
|
||||
const issue = event.target.closest('tr');
|
||||
if (!issue) {
|
||||
return;
|
||||
}
|
||||
const block = issue.closest('table');
|
||||
makeSectionVisible(block.cm);
|
||||
block.cm.focus();
|
||||
block.cm.setSelection({
|
||||
line: parseInt(issue.querySelector('td[role="line"]').textContent) - 1,
|
||||
ch: parseInt(issue.querySelector('td[role="col"]').textContent) - 1
|
||||
});
|
||||
}
|
||||
|
||||
function toggleLintReport() {
|
||||
document.getElementById('lint').classList.toggle('collapsed');
|
||||
}
|
||||
|
||||
function beautify(event) {
|
||||
if (exports.css_beautify) { // thanks to csslint's definition of 'exports'
|
||||
doBeautify();
|
||||
} else {
|
||||
const script = document.head.appendChild(document.createElement('script'));
|
||||
script.src = 'vendor-overwrites/beautify/beautify-css-mod.js';
|
||||
script.onload = doBeautify;
|
||||
}
|
||||
const script = $('script[src*="beautify-css-mod"]') ?
|
||||
[] : ['vendor-overwrites/beautify/beautify-css-mod.js'];
|
||||
onDOMscripted(script).then(doBeautify);
|
||||
|
||||
function doBeautify() {
|
||||
const tabs = prefs.get('editor.indentWithTabs');
|
||||
const options = prefs.get('editor.beautify');
|
||||
|
@ -1210,7 +1105,7 @@ function beautify(event) {
|
|||
'</div>' +
|
||||
'<div><button role="undo"></button></div>');
|
||||
|
||||
const undoButton = document.querySelector('#help-popup button[role="undo"]');
|
||||
const undoButton = $('#help-popup button[role="undo"]');
|
||||
undoButton.textContent = t(scope.length === 1 ? 'undo' : 'undoGlobal');
|
||||
undoButton.addEventListener('click', () => {
|
||||
let undoable = false;
|
||||
|
@ -1231,7 +1126,7 @@ function beautify(event) {
|
|||
[].concat.apply([], cm.doc.sel.ranges.map(r =>
|
||||
[Object.assign({}, r.anchor), Object.assign({}, r.head)]));
|
||||
const text = cm.getValue();
|
||||
const newText = exports.css_beautify(text, options);
|
||||
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
|
||||
|
@ -1249,7 +1144,7 @@ function beautify(event) {
|
|||
}, 0);
|
||||
});
|
||||
|
||||
document.querySelector('.beautify-options').onchange = ({target}) => {
|
||||
$('.beautify-options').onchange = ({target}) => {
|
||||
const value = target.type === 'checkbox' ? target.checked : target.selectedIndex > 0;
|
||||
prefs.set('editor.beautify', Object.assign(options, {[target.dataset.option]: value}));
|
||||
if (target.parentNode.hasAttribute('newline')) {
|
||||
|
@ -1275,7 +1170,8 @@ document.addEventListener('DOMContentLoaded', init);
|
|||
function init() {
|
||||
initCodeMirror();
|
||||
const params = getParams();
|
||||
if (!params.id) { // match should be 2 - one for the whole thing, one for the parentheses
|
||||
if (!params.id) {
|
||||
// match should be 2 - one for the whole thing, one for the parentheses
|
||||
// This is an add
|
||||
$('#heading').textContent = t('addStyleTitle');
|
||||
const section = {code: ''};
|
||||
|
@ -1289,7 +1185,7 @@ function init() {
|
|||
addSection(null, section);
|
||||
editors[0].setOption('lint', CodeMirror.defaults.lint);
|
||||
// default to enabled
|
||||
document.getElementById('enabled').checked = true;
|
||||
$('#enabled').checked = true;
|
||||
initHooks();
|
||||
};
|
||||
return;
|
||||
|
@ -1316,9 +1212,9 @@ function init() {
|
|||
}
|
||||
|
||||
function setStyleMeta(style) {
|
||||
document.getElementById('name').value = style.name;
|
||||
document.getElementById('enabled').checked = style.enabled;
|
||||
document.getElementById('url').href = style.url;
|
||||
$('#name').value = style.name;
|
||||
$('#enabled').checked = style.enabled;
|
||||
$('#url').href = style.url;
|
||||
}
|
||||
|
||||
function initWithStyle({style, codeIsUpdated}) {
|
||||
|
@ -1350,35 +1246,30 @@ function initWithStyle({style, codeIsUpdated}) {
|
|||
const sectionDiv = addSection(null, queue.shift());
|
||||
maximizeCodeHeight(sectionDiv, !queue.length);
|
||||
const cm = sectionDiv.CodeMirror;
|
||||
setTimeout(() => {
|
||||
cm.setOption('lint', CodeMirror.defaults.lint);
|
||||
updateLintReport(cm, 0);
|
||||
}, prefs.get('editor.lintDelay'));
|
||||
if (CodeMirror.lint) {
|
||||
setTimeout(() => {
|
||||
cm.setOption('lint', CodeMirror.defaults.lint);
|
||||
updateLintReport(cm, 0);
|
||||
}, prefs.get('editor.lintDelay'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initHooks() {
|
||||
document.querySelectorAll('#header .style-contributor').forEach(node => {
|
||||
$$('#header .style-contributor').forEach(node => {
|
||||
node.addEventListener('change', onChange);
|
||||
node.addEventListener('input', onChange);
|
||||
});
|
||||
document.getElementById('toggle-style-help').addEventListener('click', showToggleStyleHelp);
|
||||
document.getElementById('to-mozilla').addEventListener('click', showMozillaFormat, false);
|
||||
document.getElementById('to-mozilla-help').addEventListener('click', showToMozillaHelp, false);
|
||||
document.getElementById('from-mozilla').addEventListener('click', fromMozillaFormat);
|
||||
document.getElementById('beautify').addEventListener('click', beautify);
|
||||
document.getElementById('save-button').addEventListener('click', save, false);
|
||||
document.getElementById('sections-help').addEventListener('click', showSectionHelp, false);
|
||||
document.getElementById('keyMap-help').addEventListener('click', showKeyMapHelp, false);
|
||||
document.getElementById('cancel-button').addEventListener('click', goBackToManage);
|
||||
document.getElementById('lint-help').addEventListener('click', showLintHelp);
|
||||
document.getElementById('lint').addEventListener('click', gotoLintIssue);
|
||||
window.addEventListener('resize', resizeLintReport);
|
||||
|
||||
// touch devices don't have onHover events so the element we'll be toggled via clicking (touching)
|
||||
if ('ontouchstart' in document.body) {
|
||||
document.querySelector('#lint h2').addEventListener('click', toggleLintReport);
|
||||
}
|
||||
$('#toggle-style-help').addEventListener('click', showToggleStyleHelp);
|
||||
$('#to-mozilla').addEventListener('click', showMozillaFormat, false);
|
||||
$('#to-mozilla-help').addEventListener('click', showToMozillaHelp, false);
|
||||
$('#from-mozilla').addEventListener('click', fromMozillaFormat);
|
||||
$('#beautify').addEventListener('click', beautify);
|
||||
$('#save-button').addEventListener('click', save, false);
|
||||
$('#sections-help').addEventListener('click', showSectionHelp, false);
|
||||
$('#keyMap-help').addEventListener('click', showKeyMapHelp, false);
|
||||
$('#cancel-button').addEventListener('click', goBackToManage);
|
||||
initLint();
|
||||
|
||||
if (!FIREFOX) {
|
||||
$$([
|
||||
|
@ -1443,7 +1334,7 @@ function maximizeCodeHeight(sectionDiv, isLast) {
|
|||
return;
|
||||
}
|
||||
// scale heights to fill the gap between last section and bottom edge of the window
|
||||
const sections = document.getElementById('sections');
|
||||
const sections = $('#sections');
|
||||
const available = window.innerHeight - sections.getBoundingClientRect().bottom -
|
||||
parseFloat(getComputedStyle(sections).marginBottom);
|
||||
if (available <= 0) {
|
||||
|
@ -1460,25 +1351,25 @@ function maximizeCodeHeight(sectionDiv, isLast) {
|
|||
function updateTitle() {
|
||||
const DIRTY_TITLE = '* $';
|
||||
|
||||
const name = document.getElementById('name').savedValue;
|
||||
const name = $('#name').savedValue;
|
||||
const clean = isCleanGlobal();
|
||||
const title = styleId === null ? t('addStyleTitle') : t('editStyleTitle', [name]);
|
||||
document.title = clean ? title : DIRTY_TITLE.replace('$', title);
|
||||
}
|
||||
|
||||
function validate() {
|
||||
const name = document.getElementById('name').value;
|
||||
const name = $('#name').value;
|
||||
if (name === '') {
|
||||
return t('styleMissingName');
|
||||
}
|
||||
// validate the regexps
|
||||
if (document.querySelectorAll('.applies-to-list').some(list => {
|
||||
if ($$('.applies-to-list').some(list => {
|
||||
list.childNodes.some(li => {
|
||||
if (li.className === template.appliesToEverything.className) {
|
||||
return false;
|
||||
}
|
||||
const valueElement = li.querySelector('[name=applies-value]');
|
||||
const type = li.querySelector('[name=applies-type]').value;
|
||||
const valueElement = $('[name=applies-value]', li);
|
||||
const type = $('[name=applies-type]', li).value;
|
||||
const value = valueElement.value;
|
||||
if (type && value) {
|
||||
if (type === 'regexp') {
|
||||
|
@ -1498,8 +1389,14 @@ function validate() {
|
|||
return null;
|
||||
}
|
||||
|
||||
function updateLintReportIfEnabled(cm, time) {
|
||||
if (CodeMirror.lint) {
|
||||
updateLintReport(cm, time);
|
||||
}
|
||||
}
|
||||
|
||||
function save() {
|
||||
updateLintReport(null, 0);
|
||||
updateLintReportIfEnabled(null, 0);
|
||||
|
||||
// save the contents of the CodeMirror editors back into the textareas
|
||||
for (let i = 0; i < editors.length; i++) {
|
||||
|
@ -1511,8 +1408,8 @@ function save() {
|
|||
alert(error);
|
||||
return;
|
||||
}
|
||||
const name = document.getElementById('name').value;
|
||||
const enabled = document.getElementById('enabled').checked;
|
||||
const name = $('#name').value;
|
||||
const enabled = $('#enabled').checked;
|
||||
saveStyleSafe({
|
||||
id: styleId,
|
||||
name: name,
|
||||
|
@ -1539,12 +1436,12 @@ function getSectionsHashes() {
|
|||
|
||||
function getMeta(e) {
|
||||
const meta = {urls: [], urlPrefixes: [], domains: [], regexps: []};
|
||||
e.querySelector('.applies-to-list').childNodes.forEach(li => {
|
||||
$('.applies-to-list', e).childNodes.forEach(li => {
|
||||
if (li.className === template.appliesToEverything.className) {
|
||||
return;
|
||||
}
|
||||
const type = li.querySelector('[name=applies-type]').value;
|
||||
const value = li.querySelector('[name=applies-value]').value;
|
||||
const type = $('[name=applies-type]', li).value;
|
||||
const value = $('[name=applies-value]', li).value;
|
||||
if (type && value) {
|
||||
const property = CssToProperty[type];
|
||||
meta[property].push(value);
|
||||
|
@ -1593,12 +1490,12 @@ function fromMozillaFormat() {
|
|||
</div>`
|
||||
));
|
||||
|
||||
const contents = popup.querySelector('.contents');
|
||||
const contents = $('.contents', popup);
|
||||
contents.insertBefore(popup.codebox.display.wrapper, contents.firstElementChild);
|
||||
popup.codebox.focus();
|
||||
|
||||
popup.querySelector('[name="import-append"]').addEventListener('click', doImport);
|
||||
popup.querySelector('[name="import-replace"]').addEventListener('click', doImport);
|
||||
$('[name="import-append"]', popup).addEventListener('click', doImport);
|
||||
$('[name="import-replace"]', popup).addEventListener('click', doImport);
|
||||
|
||||
popup.codebox.on('change', () => {
|
||||
clearTimeout(popup.mozillaTimeout);
|
||||
|
@ -1607,9 +1504,15 @@ function fromMozillaFormat() {
|
|||
}, 100);
|
||||
});
|
||||
|
||||
function doImport() {
|
||||
const replaceOldStyle = this.name === 'import-replace';
|
||||
popup.querySelector('.dismiss').onclick();
|
||||
function doImport(event) {
|
||||
// parserlib contained in CSSLint-worker.js
|
||||
onDOMscripted(['vendor-overwrites/csslint/csslint-worker.js'])
|
||||
.then(() => doImportWhenReady(event.target));
|
||||
}
|
||||
|
||||
function doImportWhenReady(target) {
|
||||
const replaceOldStyle = target.name === 'import-replace';
|
||||
$('.dismiss', popup).onclick();
|
||||
const mozStyle = trimNewLines(popup.codebox.getValue());
|
||||
const parser = new parserlib.css.Parser();
|
||||
const lines = mozStyle.split('\n');
|
||||
|
@ -1668,7 +1571,7 @@ function fromMozillaFormat() {
|
|||
firstAddedCM.focus();
|
||||
|
||||
if (errors.length) {
|
||||
showHelp(t('issues'), $element({
|
||||
showHelp(t('linterIssues'), $element({
|
||||
tag: 'pre',
|
||||
textContent: errors.join('\n'),
|
||||
}));
|
||||
|
@ -1718,8 +1621,12 @@ function fromMozillaFormat() {
|
|||
// do onetime housekeeping as the imported text is confirmed to be a valid style
|
||||
function initFirstSection(section) {
|
||||
// skip adding the first global section when there's no code/comments
|
||||
if (!section.code.replace('@namespace url(http://www.w3.org/1999/xhtml);', '') /* ignore boilerplate NS */
|
||||
.replace(/[\s\n]/g, '')) { /* ignore all whitespace including new lines */
|
||||
if (
|
||||
/* ignore boilerplate NS */
|
||||
!section.code.replace('@namespace url(http://www.w3.org/1999/xhtml);', '')
|
||||
/* ignore all whitespace including new lines */
|
||||
.replace(/[\s\n]/g, '')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (replaceOldStyle) {
|
||||
|
@ -1728,7 +1635,7 @@ function fromMozillaFormat() {
|
|||
});
|
||||
} else if (!editors.last.getValue()) {
|
||||
// nuke the last blank section
|
||||
if (editors.last.getSection().querySelector('.applies-to-everything')) {
|
||||
if ($('.applies-to-everything', editors.last.getSection())) {
|
||||
removeSection({target: editors.last.getSection()});
|
||||
}
|
||||
}
|
||||
|
@ -1780,10 +1687,10 @@ function showKeyMapHelp() {
|
|||
'</tbody>' +
|
||||
'</table>');
|
||||
|
||||
const table = document.querySelector('#help-popup table');
|
||||
const table = $('#help-popup table');
|
||||
table.addEventListener('input', filterTable);
|
||||
|
||||
const inputs = table.querySelectorAll('input');
|
||||
const inputs = $$('input', table);
|
||||
inputs[0].addEventListener('keydown', hotkeyHandler);
|
||||
inputs[1].focus();
|
||||
|
||||
|
@ -1865,24 +1772,17 @@ function showKeyMapHelp() {
|
|||
}
|
||||
}
|
||||
|
||||
function showLintHelp() {
|
||||
showHelp(t('issues'), t('issuesHelp') + '<ul>' +
|
||||
CSSLint.getRules().map(rule =>
|
||||
'<li><b>' + rule.name + '</b><br>' + rule.desc + '</li>'
|
||||
).join('') + '</ul>'
|
||||
);
|
||||
}
|
||||
|
||||
function showRegExpTester(event, section = getSectionForChild(this)) {
|
||||
const GET_FAVICON_URL = 'https://www.google.com/s2/favicons?domain=';
|
||||
const OWN_ICON = chrome.runtime.getManifest().icons['16'];
|
||||
const cachedRegexps = showRegExpTester.cachedRegexps =
|
||||
showRegExpTester.cachedRegexps || new Map();
|
||||
const regexps = [...section.querySelector('.applies-to-list').children]
|
||||
const regexps = [...$('.applies-to-list', section).children]
|
||||
.map(item =>
|
||||
!item.matches('.applies-to-everything') &&
|
||||
item.querySelector('.applies-type').value === 'regexp' &&
|
||||
item.querySelector('.applies-value').value.trim())
|
||||
$('.applies-type', item).value === 'regexp' &&
|
||||
$('.applies-value', item).value.trim()
|
||||
)
|
||||
.filter(item => item)
|
||||
.map(text => {
|
||||
const rxData = Object.assign({text}, cachedRegexps.get(text));
|
||||
|
@ -1895,7 +1795,7 @@ function showRegExpTester(event, section = getSectionForChild(this)) {
|
|||
return rxData;
|
||||
});
|
||||
chrome.tabs.onUpdated.addListener(function _(tabId, info) {
|
||||
if (document.querySelector('.regexp-report')) {
|
||||
if ($('.regexp-report')) {
|
||||
if (info.url) {
|
||||
showRegExpTester(event, section);
|
||||
}
|
||||
|
@ -2003,7 +1903,7 @@ function showRegExpTester(event, section = getSectionForChild(this)) {
|
|||
}
|
||||
showHelp(t('styleRegexpTestTitle'), report);
|
||||
|
||||
document.querySelector('.regexp-report').onclick = event => {
|
||||
$('.regexp-report').onclick = event => {
|
||||
const target = event.target.closest('a, .regexp-report div');
|
||||
if (target) {
|
||||
openURL({url: target.href || target.textContent});
|
||||
|
@ -2022,7 +1922,8 @@ function showHelp(title, body) {
|
|||
|
||||
if (getComputedStyle(div).display === 'none') {
|
||||
document.addEventListener('keydown', closeHelp);
|
||||
div.querySelector('.dismiss').onclick = closeHelp; // avoid chaining on multiple showHelp() calls
|
||||
// avoid chaining on multiple showHelp() calls
|
||||
$('.dismiss', div).onclick = closeHelp;
|
||||
}
|
||||
|
||||
div.style.display = 'block';
|
||||
|
@ -2035,7 +1936,9 @@ function showHelp(title, body) {
|
|||
((e.keyCode || e.which) === 27 && !e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey)
|
||||
) {
|
||||
div.style.display = '';
|
||||
document.querySelector('.contents').textContent = '';
|
||||
const contents = $('.contents');
|
||||
contents.textContent = '';
|
||||
clearTimeout(contents.timer);
|
||||
document.removeEventListener('keydown', closeHelp);
|
||||
}
|
||||
}
|
||||
|
@ -2045,14 +1948,14 @@ function showCodeMirrorPopup(title, html, options) {
|
|||
const popup = showHelp(title, html);
|
||||
popup.classList.add('big');
|
||||
|
||||
popup.codebox = CodeMirror(popup.querySelector('.contents'), Object.assign({
|
||||
popup.codebox = CodeMirror($('.contents', popup), Object.assign({
|
||||
mode: 'css',
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
foldGutter: true,
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
|
||||
matchBrackets: true,
|
||||
lint: {getAnnotations: CodeMirror.lint.css, delay: 0},
|
||||
lint: getLinterConfigForCodeMirror(prefs.get('editor.linter')),
|
||||
styleActiveLine: true,
|
||||
theme: prefs.get('editor.theme'),
|
||||
keyMap: prefs.get('editor.keyMap')
|
||||
|
|
432
edit/lint.js
Normal file
432
edit/lint.js
Normal file
|
@ -0,0 +1,432 @@
|
|||
/* global CodeMirror messageBox */
|
||||
/* global editors makeSectionVisible showCodeMirrorPopup showHelp */
|
||||
/* global stylelintDefaultConfig csslintDefaultConfig onDOMscripted injectCSS require */
|
||||
'use strict';
|
||||
|
||||
function initLint() {
|
||||
$('#lint-help').addEventListener('click', showLintHelp);
|
||||
$('#lint').addEventListener('click', gotoLintIssue);
|
||||
window.addEventListener('resize', resizeLintReport);
|
||||
$('#linter-settings').addEventListener('click', openStylelintSettings);
|
||||
|
||||
// touch devices don't have onHover events so the element we'll be toggled via clicking (touching)
|
||||
if ('ontouchstart' in document.body) {
|
||||
$('#lint h2').addEventListener('click', toggleLintReport);
|
||||
}
|
||||
// initialize storage of linter config
|
||||
BG.chromeSync.getValue('editorStylelintConfig').then(config => setStylelintConfig(config));
|
||||
BG.chromeSync.getValue('editorCSSLintConfig').then(config => setCSSLintConfig(config));
|
||||
}
|
||||
|
||||
function setStylelintConfig(config) {
|
||||
// can't use default parameters, because config may be null
|
||||
if (Object.keys(config || []).length === 0 && typeof stylelintDefaultConfig !== 'undefined') {
|
||||
config = deepCopy(stylelintDefaultConfig.rules);
|
||||
}
|
||||
BG.chromeSync.setValue('editorStylelintConfig', config);
|
||||
return config;
|
||||
}
|
||||
|
||||
function setCSSLintConfig(config) {
|
||||
if (Object.keys(config || []).length === 0 && typeof csslintDefaultConfig !== 'undefined') {
|
||||
config = Object.assign({}, csslintDefaultConfig);
|
||||
}
|
||||
BG.chromeSync.setValue('editorCSSLintConfig', config);
|
||||
return config;
|
||||
}
|
||||
|
||||
function getLinterConfigForCodeMirror(name) {
|
||||
return CodeMirror.lint && CodeMirror.lint[name] ? {
|
||||
getAnnotations: CodeMirror.lint[name],
|
||||
delay: prefs.get('editor.lintDelay')
|
||||
} : false;
|
||||
}
|
||||
|
||||
function updateLinter(linter) {
|
||||
function updateEditors() {
|
||||
const options = getLinterConfigForCodeMirror(linter);
|
||||
CodeMirror.defaults.lint = options === 'null' ? false : options;
|
||||
editors.forEach(cm => {
|
||||
// set lint to "null" to disable
|
||||
cm.setOption('lint', options);
|
||||
// enabling/disabling linting changes the gutter width
|
||||
cm.refresh();
|
||||
updateLintReport(cm, 200);
|
||||
});
|
||||
}
|
||||
// load scripts
|
||||
loadSelectedLinter(linter).then(() => {
|
||||
updateEditors();
|
||||
});
|
||||
$('#linter-settings').style.display = linter === 'null' ? 'none' : 'inline-block';
|
||||
}
|
||||
|
||||
function updateLintReport(cm, delay) {
|
||||
if (delay === 0) {
|
||||
// immediately show pending csslint/stylelint messages in onbeforeunload and save
|
||||
update(cm);
|
||||
return;
|
||||
}
|
||||
if (delay > 0) {
|
||||
setTimeout(cm => {
|
||||
cm.performLint();
|
||||
update(cm);
|
||||
}, delay, cm);
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line no-var
|
||||
var state = cm.state.lint;
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
// user is editing right now: postpone updating the report for the new issues (default: 500ms lint + 4500ms)
|
||||
// or update it as soon as possible (default: 500ms lint + 100ms) in case an existing issue was just fixed
|
||||
clearTimeout(state.reportTimeout);
|
||||
state.reportTimeout = setTimeout(update, state.options.delay + 100, cm);
|
||||
state.postponeNewIssues = delay === undefined || delay === null;
|
||||
|
||||
function update(cm) {
|
||||
const scope = cm ? [cm] : editors;
|
||||
let changed = false;
|
||||
let fixedOldIssues = false;
|
||||
scope.forEach(cm => {
|
||||
const scopedState = cm.state.lint || {};
|
||||
const oldMarkers = scopedState.markedLast || {};
|
||||
const newMarkers = {};
|
||||
const html = !scopedState.marked || scopedState.marked.length === 0 ? '' : '<tbody>' +
|
||||
scopedState.marked.map(mark => {
|
||||
const info = mark.__annotation;
|
||||
const isActiveLine = info.from.line === cm.getCursor().line;
|
||||
const pos = isActiveLine ? 'cursor' : (info.from.line + ',' + info.from.ch);
|
||||
// stylelint rule added in parentheses at the end; extract it out for the stylelint info popup
|
||||
const lintRuleName = info.message
|
||||
.substring(info.message.lastIndexOf('('), info.message.length)
|
||||
.replace(/[()]/g, '');
|
||||
const title = escapeHtml(info.message);
|
||||
const message = title.length > 100 ? title.substr(0, 100) + '...' : title;
|
||||
if (isActiveLine || oldMarkers[pos] === message) {
|
||||
delete oldMarkers[pos];
|
||||
}
|
||||
newMarkers[pos] = message;
|
||||
return `<tr class="${info.severity}">
|
||||
<td role="severity" data-rule="${lintRuleName}">
|
||||
<div class="CodeMirror-lint-marker-${info.severity}">${info.severity}</div>
|
||||
</td>
|
||||
<td role="line">${info.from.line + 1}</td>
|
||||
<td role="sep">:</td>
|
||||
<td role="col">${info.from.ch + 1}</td>
|
||||
<td role="message" title="${title}">${message}</td>
|
||||
</tr>`;
|
||||
}).join('') + '</tbody>';
|
||||
scopedState.markedLast = newMarkers;
|
||||
fixedOldIssues |= scopedState.reportDisplayed && Object.keys(oldMarkers).length > 0;
|
||||
if (scopedState.html !== html) {
|
||||
scopedState.html = html;
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
clearTimeout(state ? state.renderTimeout : undefined);
|
||||
if (!state || !state.postponeNewIssues || fixedOldIssues) {
|
||||
renderLintReport(true);
|
||||
} else {
|
||||
state.renderTimeout = setTimeout(() => {
|
||||
renderLintReport(true);
|
||||
}, CodeMirror.defaults.lintReportDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
function escapeHtml(html) {
|
||||
const chars = {'&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/'};
|
||||
return html.replace(/[&<>"'/]/g, char => chars[char]);
|
||||
}
|
||||
}
|
||||
|
||||
function renderLintReport(someBlockChanged) {
|
||||
const container = $('#lint');
|
||||
const content = container.children[1];
|
||||
const label = t('sectionCode');
|
||||
const newContent = content.cloneNode(false);
|
||||
let issueCount = 0;
|
||||
editors.forEach((cm, index) => {
|
||||
if (cm.state.lint && cm.state.lint.html) {
|
||||
const html = '<caption>' + label + ' ' + (index + 1) + '</caption>' + cm.state.lint.html;
|
||||
const newBlock = newContent.appendChild(tHTML(html, 'table'));
|
||||
|
||||
newBlock.cm = cm;
|
||||
issueCount += newBlock.rows.length;
|
||||
|
||||
const block = content.children[newContent.children.length - 1];
|
||||
const blockChanged = !block || cm !== block.cm || html !== block.innerHTML;
|
||||
someBlockChanged |= blockChanged;
|
||||
cm.state.lint.reportDisplayed = blockChanged;
|
||||
}
|
||||
});
|
||||
if (someBlockChanged || newContent.children.length !== content.children.length) {
|
||||
$('#issue-count').textContent = issueCount;
|
||||
container.replaceChild(newContent, content);
|
||||
container.style.display = newContent.children.length ? 'block' : 'none';
|
||||
resizeLintReport();
|
||||
}
|
||||
}
|
||||
|
||||
function resizeLintReport() {
|
||||
// subtracted value to prevent scrollbar
|
||||
const magicBuffer = 20;
|
||||
const content = $('#lint table');
|
||||
if (content) {
|
||||
const bounds = content.getBoundingClientRect();
|
||||
const newMaxHeight = bounds.bottom <= window.innerHeight ? '' :
|
||||
// subtract out a bit of padding or the vertical scrollbar extends beyond the viewport
|
||||
(window.innerHeight - bounds.top - magicBuffer) + 'px';
|
||||
if (newMaxHeight !== content.style.maxHeight) {
|
||||
content.parentNode.style.maxHeight = newMaxHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function gotoLintIssue(event) {
|
||||
const issue = event.target.closest('tr');
|
||||
if (!issue) {
|
||||
return;
|
||||
}
|
||||
const block = issue.closest('table');
|
||||
makeSectionVisible(block.cm);
|
||||
block.cm.focus();
|
||||
block.cm.setSelection({
|
||||
line: parseInt($('td[role="line"]', issue).textContent) - 1,
|
||||
ch: parseInt($('td[role="col"]', issue).textContent) - 1
|
||||
});
|
||||
}
|
||||
|
||||
function toggleLintReport() {
|
||||
$('#lint').classList.toggle('collapsed');
|
||||
}
|
||||
|
||||
function showLintHelp() {
|
||||
const makeLink = (url, txt) => `<a target="_blank" href="${url}">${txt}</a>`;
|
||||
const linter = prefs.get('editor.linter');
|
||||
const url = linter === 'stylelint'
|
||||
? 'https://stylelint.io/user-guide/rules/'
|
||||
// some CSSLint rules do not have a url
|
||||
: 'https://github.com/CSSLint/csslint/issues/535';
|
||||
const rules = [];
|
||||
let template;
|
||||
let list = '<ul class="rules">';
|
||||
let header = '';
|
||||
if (linter === 'csslint') {
|
||||
const CSSLintRules = window.CSSLint.getRules();
|
||||
const findCSSLintRule = id => CSSLintRules.find(rule => rule.id === id);
|
||||
header = t('linterIssuesHelp', makeLink('https://github.com/CSSLint/csslint/wiki/Rules-by-ID', 'CSSLint'));
|
||||
template = ruleID => {
|
||||
const rule = findCSSLintRule(ruleID);
|
||||
return rule ? `<li><b>${makeLink(rule.url || url, rule.name)}</b><br>${rule.desc}</li>` : '';
|
||||
};
|
||||
} else {
|
||||
header = t('linterIssuesHelp', makeLink(url, 'stylelint'));
|
||||
template = rule => `<li>${makeLink(url + rule, rule)}</li>`;
|
||||
}
|
||||
// Only show rules with issues in the popup
|
||||
$$('#lint td[role="severity"]').forEach(el => {
|
||||
const rule = el.dataset.rule;
|
||||
if (!rules.includes(rule)) {
|
||||
list += template(rule);
|
||||
rules.push(rule);
|
||||
}
|
||||
});
|
||||
return showHelp(t('linterIssues'), header + list + '</ul>');
|
||||
}
|
||||
|
||||
function showLinterErrorMessage(title, contents) {
|
||||
messageBox({
|
||||
title,
|
||||
contents,
|
||||
className: 'danger center lint-config',
|
||||
buttons: [t('confirmOK')],
|
||||
});
|
||||
}
|
||||
|
||||
function showSavedMessage() {
|
||||
$('#help-popup .saved-message').classList.add('show');
|
||||
clearTimeout($('#help-popup .contents').timer);
|
||||
$('#help-popup .contents').timer = setTimeout(() => {
|
||||
// popup may be closed at this point
|
||||
const msg = $('#help-popup .saved-message');
|
||||
if (msg) {
|
||||
msg.classList.remove('show');
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function checkLinter(linter = prefs.get('editor.linter')) {
|
||||
linter = linter.toLowerCase();
|
||||
if (prefs.get('editor.linter') !== linter) {
|
||||
prefs.set('editor.linter', linter);
|
||||
}
|
||||
return linter;
|
||||
}
|
||||
|
||||
function checkConfigRules(linter, config) {
|
||||
const invalid = [];
|
||||
const linterRules = linter === 'stylelint'
|
||||
? Object.keys(window.stylelint.rules)
|
||||
: window.CSSLint.getRules().map(rule => rule.id);
|
||||
Object.keys(config).forEach(setting => {
|
||||
if (!linterRules.includes(setting)) {
|
||||
invalid.push(setting);
|
||||
}
|
||||
});
|
||||
return invalid;
|
||||
}
|
||||
|
||||
function stringifyConfig(config) {
|
||||
return JSON.stringify(config, null, 2)
|
||||
.replace(/,\n\s+\{\n\s+("severity":\s"\w+")\n\s+\}/g, ', {$1}');
|
||||
}
|
||||
|
||||
function setupLinterSettingsEvents(popup) {
|
||||
$('.save', popup).addEventListener('click', event => {
|
||||
event.preventDefault();
|
||||
const linter = checkLinter(event.target.dataset.linter);
|
||||
const json = tryJSONparse(popup.codebox.getValue());
|
||||
if (json) {
|
||||
const invalid = checkConfigRules(linter, json);
|
||||
if (invalid.length) {
|
||||
return showLinterErrorMessage(
|
||||
linter,
|
||||
t('linterInvalidConfigError') + `<ul><li>${invalid.join('</li><li>')}</li></ul>`
|
||||
);
|
||||
}
|
||||
if (linter === 'stylelint') {
|
||||
setStylelintConfig(json);
|
||||
} else {
|
||||
setCSSLintConfig(json);
|
||||
}
|
||||
updateLinter(linter);
|
||||
showSavedMessage();
|
||||
} else {
|
||||
showLinterErrorMessage(linter, t('linterJSONError'));
|
||||
}
|
||||
popup.codebox.focus();
|
||||
});
|
||||
$('.reset', popup).addEventListener('click', event => {
|
||||
event.preventDefault();
|
||||
const linter = checkLinter(event.target.dataset.linter);
|
||||
let config;
|
||||
if (linter === 'stylelint') {
|
||||
setStylelintConfig();
|
||||
config = stylelintDefaultConfig.rules;
|
||||
} else {
|
||||
setCSSLintConfig();
|
||||
config = csslintDefaultConfig;
|
||||
}
|
||||
popup.codebox.setValue(stringifyConfig(config));
|
||||
popup.codebox.focus();
|
||||
});
|
||||
$('.cancel', popup).addEventListener('click', event => {
|
||||
event.preventDefault();
|
||||
$('.dismiss').dispatchEvent(new Event('click'));
|
||||
});
|
||||
}
|
||||
|
||||
function openStylelintSettings() {
|
||||
const linter = prefs.get('editor.linter');
|
||||
BG.chromeSync.getValue(
|
||||
linter === 'stylelint'
|
||||
? 'editorStylelintConfig'
|
||||
: 'editorCSSLintConfig'
|
||||
).then(config => {
|
||||
if (!config || config.length === 0) {
|
||||
config = linter === 'stylelint'
|
||||
? setStylelintConfig(config)
|
||||
: setCSSLintConfig(config);
|
||||
}
|
||||
const configString = stringifyConfig(config);
|
||||
setupLinterPopup(configString);
|
||||
});
|
||||
}
|
||||
|
||||
function setupLinterPopup(config) {
|
||||
const linter = prefs.get('editor.linter');
|
||||
const linterTitle = linter === 'stylelint' ? 'Stylelint' : 'CSSLint';
|
||||
function makeButton(className, text, options = {}) {
|
||||
return $element(Object.assign(options, {
|
||||
tag: 'button',
|
||||
className,
|
||||
type: 'button',
|
||||
textContent: t(text),
|
||||
dataset: {linter}
|
||||
}));
|
||||
}
|
||||
function makeLink(url, textContent) {
|
||||
return $element({tag: 'a', target: '_blank', href: url, textContent});
|
||||
}
|
||||
function setJSONMode(cm) {
|
||||
cm.setOption('mode', 'application/json');
|
||||
cm.setOption('lint', 'json');
|
||||
}
|
||||
const popup = showCodeMirrorPopup(t('linterConfigPopupTitle', linterTitle), $element({
|
||||
appendChild: [
|
||||
$element({
|
||||
tag: 'p',
|
||||
appendChild: [
|
||||
t('linterRulesLink') + ' ',
|
||||
makeLink(
|
||||
linter === 'stylelint'
|
||||
? 'https://stylelint.io/user-guide/rules/'
|
||||
: 'https://github.com/CSSLint/csslint/wiki/Rules-by-ID',
|
||||
linterTitle
|
||||
),
|
||||
linter === 'csslint' ? ' ' + t('linterCSSLintSettings') : ''
|
||||
]
|
||||
}),
|
||||
makeButton('save', 'styleSaveLabel'),
|
||||
makeButton('cancel', 'confirmCancel'),
|
||||
makeButton('reset', 'genericResetLabel', {title: t('linterResetMessage')}),
|
||||
$element({
|
||||
tag: 'span',
|
||||
className: 'saved-message',
|
||||
textContent: t('genericSavedMessage')
|
||||
})
|
||||
]
|
||||
}));
|
||||
const contents = $('.contents', popup);
|
||||
const loadJSON = window.jsonlint ? [] : [
|
||||
'vendor/codemirror/mode/javascript/javascript.js',
|
||||
'vendor/codemirror/addon/lint/json-lint.js',
|
||||
'vendor/jsonlint/jsonlint.js'
|
||||
];
|
||||
contents.insertBefore(popup.codebox.display.wrapper, contents.firstElementChild);
|
||||
popup.codebox.focus();
|
||||
popup.codebox.setValue(config);
|
||||
popup.codebox.clearHistory();
|
||||
onDOMscripted(loadJSON).then(() => setJSONMode(popup.codebox));
|
||||
setupLinterSettingsEvents(popup);
|
||||
}
|
||||
|
||||
function loadSelectedLinter(name) {
|
||||
const scripts = [];
|
||||
if (name !== 'null' && !$('script[src*="css-lint.js"]')) {
|
||||
// inject css
|
||||
injectCSS('vendor/codemirror/addon/lint/lint.css');
|
||||
injectCSS('msgbox/msgbox.css');
|
||||
// load CodeMirror lint code
|
||||
scripts.push(
|
||||
'vendor/codemirror/addon/lint/lint.js',
|
||||
'vendor-overwrites/codemirror/addon/lint/css-lint.js',
|
||||
'msgbox/msgbox.js'
|
||||
);
|
||||
}
|
||||
if (name === 'csslint' && !window.CSSLint) {
|
||||
scripts.push(
|
||||
'edit/csslint-config.js',
|
||||
'vendor-overwrites/csslint/csslint-worker.js'
|
||||
);
|
||||
} else if (name === 'stylelint' && !window.stylelint) {
|
||||
scripts.push(
|
||||
'vendor-overwrites/stylelint/stylelint-bundle.min.js',
|
||||
'edit/stylelint-config.js'
|
||||
);
|
||||
}
|
||||
return onDOMscripted(scripts);
|
||||
}
|
170
edit/stylelint-config.js
Normal file
170
edit/stylelint-config.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
'use strict';
|
||||
|
||||
window.stylelintDefaultConfig = (defaultSeverity => ({
|
||||
// 'sugarss' is a indent-based syntax like Sass or Stylus
|
||||
// ref: https://github.com/postcss/postcss#syntaxes
|
||||
syntax: 'sugarss',
|
||||
// ** recommended rules **
|
||||
// ref: https://github.com/stylelint/stylelint-config-recommended/blob/master/index.js
|
||||
rules: {
|
||||
'at-rule-no-unknown': [true, defaultSeverity],
|
||||
'block-no-empty': [true, defaultSeverity],
|
||||
'color-no-invalid-hex': [true, defaultSeverity],
|
||||
'declaration-block-no-duplicate-properties': [true, {
|
||||
'ignore': ['consecutive-duplicates-with-different-values'],
|
||||
'severity': 'warning'
|
||||
}],
|
||||
'declaration-block-no-shorthand-property-overrides': [true, defaultSeverity],
|
||||
'font-family-no-duplicate-names': [true, defaultSeverity],
|
||||
'function-calc-no-unspaced-operator': [true, defaultSeverity],
|
||||
'function-linear-gradient-no-nonstandard-direction': [true, defaultSeverity],
|
||||
'keyframe-declaration-no-important': [true, defaultSeverity],
|
||||
'media-feature-name-no-unknown': [true, defaultSeverity],
|
||||
/* recommended true */
|
||||
'no-empty-source': false,
|
||||
'no-extra-semicolons': [true, defaultSeverity],
|
||||
'no-invalid-double-slash-comments': [true, defaultSeverity],
|
||||
'property-no-unknown': [true, defaultSeverity],
|
||||
'selector-pseudo-class-no-unknown': [true, defaultSeverity],
|
||||
'selector-pseudo-element-no-unknown': [true, defaultSeverity],
|
||||
'selector-type-no-unknown': [true, defaultSeverity],
|
||||
'string-no-newline': [true, defaultSeverity],
|
||||
'unit-no-unknown': [true, defaultSeverity],
|
||||
|
||||
// ** non-essential rules
|
||||
'comment-no-empty': false,
|
||||
'declaration-block-no-redundant-longhand-properties': false,
|
||||
'shorthand-property-no-redundant-values': false,
|
||||
|
||||
// ** stylistic rules **
|
||||
/*
|
||||
'at-rule-empty-line-before': [
|
||||
'always',
|
||||
{
|
||||
'except': [
|
||||
'blockless-after-same-name-blockless',
|
||||
'first-nested'
|
||||
],
|
||||
'ignore': [
|
||||
'after-comment'
|
||||
]
|
||||
}
|
||||
],
|
||||
'at-rule-name-case': 'lower',
|
||||
'at-rule-name-space-after': 'always-single-line',
|
||||
'at-rule-semicolon-newline-after': 'always',
|
||||
'block-closing-brace-empty-line-before': 'never',
|
||||
'block-closing-brace-newline-after': 'always',
|
||||
'block-closing-brace-newline-before': 'always-multi-line',
|
||||
'block-closing-brace-space-before': 'always-single-line',
|
||||
'block-opening-brace-newline-after': 'always-multi-line',
|
||||
'block-opening-brace-space-after': 'always-single-line',
|
||||
'block-opening-brace-space-before': 'always',
|
||||
'color-hex-case': 'lower',
|
||||
'color-hex-length': 'short',
|
||||
'comment-empty-line-before': [
|
||||
'always',
|
||||
{
|
||||
'except': [
|
||||
'first-nested'
|
||||
],
|
||||
'ignore': [
|
||||
'stylelint-commands'
|
||||
]
|
||||
}
|
||||
],
|
||||
'comment-whitespace-inside': 'always',
|
||||
'custom-property-empty-line-before': [
|
||||
'always',
|
||||
{
|
||||
'except': [
|
||||
'after-custom-property',
|
||||
'first-nested'
|
||||
],
|
||||
'ignore': [
|
||||
'after-comment',
|
||||
'inside-single-line-block'
|
||||
]
|
||||
}
|
||||
],
|
||||
'declaration-bang-space-after': 'never',
|
||||
'declaration-bang-space-before': 'always',
|
||||
'declaration-block-semicolon-newline-after': 'always-multi-line',
|
||||
'declaration-block-semicolon-space-after': 'always-single-line',
|
||||
'declaration-block-semicolon-space-before': 'never',
|
||||
'declaration-block-single-line-max-declarations': 1,
|
||||
'declaration-block-trailing-semicolon': 'always',
|
||||
'declaration-colon-newline-after': 'always-multi-line',
|
||||
'declaration-colon-space-after': 'always-single-line',
|
||||
'declaration-colon-space-before': 'never',
|
||||
'declaration-empty-line-before': [
|
||||
'always',
|
||||
{
|
||||
'except': [
|
||||
'after-declaration',
|
||||
'first-nested'
|
||||
],
|
||||
'ignore': [
|
||||
'after-comment',
|
||||
'inside-single-line-block'
|
||||
]
|
||||
}
|
||||
],
|
||||
'function-comma-newline-after': 'always-multi-line',
|
||||
'function-comma-space-after': 'always-single-line',
|
||||
'function-comma-space-before': 'never',
|
||||
'function-max-empty-lines': 0,
|
||||
'function-name-case': 'lower',
|
||||
'function-parentheses-newline-inside': 'always-multi-line',
|
||||
'function-parentheses-space-inside': 'never-single-line',
|
||||
'function-whitespace-after': 'always',
|
||||
'indentation': 2,
|
||||
'length-zero-no-unit': true,
|
||||
'max-empty-lines': 1,
|
||||
'media-feature-colon-space-after': 'always',
|
||||
'media-feature-colon-space-before': 'never',
|
||||
'media-feature-name-case': 'lower',
|
||||
'media-feature-parentheses-space-inside': 'never',
|
||||
'media-feature-range-operator-space-after': 'always',
|
||||
'media-feature-range-operator-space-before': 'always',
|
||||
'media-query-list-comma-newline-after': 'always-multi-line',
|
||||
'media-query-list-comma-space-after': 'always-single-line',
|
||||
'media-query-list-comma-space-before': 'never',
|
||||
'no-eol-whitespace': true,
|
||||
'no-missing-end-of-source-newline': true,
|
||||
'number-leading-zero': 'always',
|
||||
'number-no-trailing-zeros': true,
|
||||
'property-case': 'lower',
|
||||
'rule-empty-line-before': [
|
||||
'always-multi-line',
|
||||
{
|
||||
'except': [
|
||||
'first-nested'
|
||||
],
|
||||
'ignore': [
|
||||
'after-comment'
|
||||
]
|
||||
}
|
||||
],
|
||||
'selector-attribute-brackets-space-inside': 'never',
|
||||
'selector-attribute-operator-space-after': 'never',
|
||||
'selector-attribute-operator-space-before': 'never',
|
||||
'selector-combinator-space-after': 'always',
|
||||
'selector-combinator-space-before': 'always',
|
||||
'selector-descendant-combinator-no-non-space': true,
|
||||
'selector-list-comma-newline-after': 'always',
|
||||
'selector-list-comma-space-before': 'never',
|
||||
'selector-max-empty-lines': 0,
|
||||
'selector-pseudo-class-case': 'lower',
|
||||
'selector-pseudo-class-parentheses-space-inside': 'never',
|
||||
'selector-pseudo-element-case': 'lower',
|
||||
'selector-pseudo-element-colon-notation': 'double',
|
||||
'selector-type-case': 'lower',
|
||||
'unit-case': 'lower',
|
||||
'value-list-comma-newline-after': 'always-multi-line',
|
||||
'value-list-comma-space-after': 'always-single-line',
|
||||
'value-list-comma-space-before': 'never',
|
||||
'value-list-max-empty-lines': 0
|
||||
*/
|
||||
}
|
||||
}))({severity: 'warning'});
|
80
js/dom.js
80
js/dom.js
|
@ -67,6 +67,86 @@ function onDOMready() {
|
|||
}
|
||||
|
||||
|
||||
function onDOMscripted(scripts) {
|
||||
if (scripts) {
|
||||
return new Promise(resolve => {
|
||||
addResolver(resolve);
|
||||
onDOMscripted.scriptQueue = scripts;
|
||||
loadNextScript();
|
||||
});
|
||||
}
|
||||
if (onDOMscripted.scriptQueue) {
|
||||
return new Promise(resolve => addResolver(resolve));
|
||||
}
|
||||
if (document.readyState !== 'loading') {
|
||||
if (onDOMscripted.resolveOnReady) {
|
||||
onDOMscripted.resolveOnReady.forEach(r => r());
|
||||
onDOMscripted.resolveOnReady = null;
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
return onDOMready().then(onDOMscripted);
|
||||
|
||||
function loadNextScript() {
|
||||
const next = onDOMscripted.scriptQueue.shift();
|
||||
if (!next) {
|
||||
onDOMscripted.scriptQueue = null;
|
||||
onDOMscripted();
|
||||
} else if (typeof next === 'function') {
|
||||
Promise.resolve(next())
|
||||
.then(loadNextScript);
|
||||
} else {
|
||||
Promise.all(
|
||||
(next instanceof Array ? next : [next]).map(next =>
|
||||
typeof next === 'function'
|
||||
? next()
|
||||
: injectScript({src: next, async: true})
|
||||
)
|
||||
).then(loadNextScript);
|
||||
}
|
||||
}
|
||||
|
||||
function addResolver(r) {
|
||||
if (!onDOMscripted.resolveOnReady) {
|
||||
onDOMscripted.resolveOnReady = [];
|
||||
}
|
||||
onDOMscripted.resolveOnReady.push(r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function injectScript(properties) {
|
||||
if (typeof properties === 'string') {
|
||||
properties = {src: properties};
|
||||
}
|
||||
if (!properties || !properties.src) {
|
||||
return;
|
||||
}
|
||||
const script = document.head.appendChild(document.createElement('script'));
|
||||
Object.assign(script, properties);
|
||||
if (!properties.onload) {
|
||||
return new Promise(resolve => {
|
||||
script.onload = () => {
|
||||
script.onload = null;
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function injectCSS(url) {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
document.head.appendChild($element({
|
||||
tag: 'link',
|
||||
rel: 'stylesheet',
|
||||
href: url
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
function scrollElementIntoView(element) {
|
||||
// align to the top/bottom of the visible area if wasn't visible
|
||||
const bounds = element.getBoundingClientRect();
|
||||
|
|
|
@ -42,6 +42,7 @@ var prefs = new function Prefs() {
|
|||
indent_conditional: true,
|
||||
},
|
||||
'editor.lintDelay': 500, // lint gutter marker update delay, ms
|
||||
'editor.linter': 'csslint', // Choose csslint or stylelint
|
||||
'editor.lintReportDelay': 4500, // lint report update delay, ms
|
||||
'editor.matchHighlight': 'token', // token = token/word under cursor even if nothing is selected
|
||||
// selection = only when something is selected
|
||||
|
@ -321,11 +322,11 @@ var prefs = new function Prefs() {
|
|||
// and establishes a two-way connection between the document elements and the actual prefs
|
||||
function setupLivePrefs(
|
||||
IDs = Object.getOwnPropertyNames(prefs.readOnlyValues)
|
||||
.filter(id => document.getElementById(id))
|
||||
.filter(id => $('#' + id))
|
||||
) {
|
||||
const checkedProps = {};
|
||||
for (const id of IDs) {
|
||||
const element = document.getElementById(id);
|
||||
const element = $('#' + id);
|
||||
checkedProps[id] = element.type === 'checkbox' ? 'checked' : 'value';
|
||||
updateElement({id, element, force: true});
|
||||
element.addEventListener('change', onChange);
|
||||
|
@ -341,7 +342,7 @@ function setupLivePrefs(
|
|||
function updateElement({
|
||||
id,
|
||||
value = prefs.get(id),
|
||||
element = document.getElementById(id),
|
||||
element = $('#' + id),
|
||||
force,
|
||||
}) {
|
||||
const prop = checkedProps[id];
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"background": {
|
||||
"scripts": [
|
||||
"js/messaging.js",
|
||||
"vendor-overwrites/lz-string/LZString-2xspeedup.js",
|
||||
"background/storage.js",
|
||||
"js/prefs.js",
|
||||
"background/background.js",
|
||||
|
|
|
@ -143,7 +143,8 @@ function initPopup(url) {
|
|||
title: `url-prefix("${url}")`,
|
||||
textContent: prefs.get('popup.breadcrumbs.usePath')
|
||||
? new URL(url).pathname.slice(1)
|
||||
: t('writeStyleForURL').replace(/ /g, '\u00a0'), // this URL
|
||||
// this URL
|
||||
: t('writeStyleForURL').replace(/ /g, '\u00a0'),
|
||||
onclick: handleEvent.openLink,
|
||||
});
|
||||
if (prefs.get('popup.breadcrumbs')) {
|
||||
|
|
158
vendor-overwrites/codemirror/addon/lint/css-lint.js
vendored
158
vendor-overwrites/codemirror/addon/lint/css-lint.js
vendored
|
@ -3,62 +3,112 @@
|
|||
|
||||
// Depends on csslint.js from https://github.com/stubbornella/csslint
|
||||
|
||||
// declare global: CSSLint
|
||||
/* global CodeMirror require define */
|
||||
/* global CSSLint stylelint stylelintDefaultConfig csslintDefaultConfig */
|
||||
'use strict';
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
(mod => {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
// CommonJS
|
||||
mod(require('../../lib/codemirror'));
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
// AMD
|
||||
define(['../../lib/codemirror'], mod);
|
||||
} else {
|
||||
// Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerHelper("lint", "css", function(text) {
|
||||
var found = [];
|
||||
if (!window.CSSLint) return found;
|
||||
|
||||
/* STYLISH: hack start (part 1) */
|
||||
var rules = CSSLint.getRules();
|
||||
var allowedRules = ["display-property-grouping", "duplicate-properties", "empty-rules", "errors", "known-properties"];
|
||||
CSSLint.clearRules();
|
||||
rules.forEach(function(rule) {
|
||||
if (allowedRules.indexOf(rule.id) >= 0) {
|
||||
CSSLint.addRule(rule);
|
||||
}
|
||||
});
|
||||
/* STYLISH: hack end */
|
||||
|
||||
var results = CSSLint.verify(text), messages = results.messages, message = null;
|
||||
for ( var i = 0; i < messages.length; i++) {
|
||||
message = messages[i];
|
||||
|
||||
/* STYLISH: hack start (part 2) */
|
||||
if (message.type === 'warning') {
|
||||
// @font-face {font-family: 'Ampersand'; unicode-range: U+26;}
|
||||
if (message.message.indexOf('unicode-range') !== -1) {
|
||||
continue;
|
||||
}
|
||||
else if ( // color: hsl(210, 100%, 2.2%); or color: hsla(210, 100%, 2.2%, 0.3);
|
||||
message.message.startsWith('Expected (<color>) but found \'hsl') &&
|
||||
/hsla?\(\s*(-?\d+)%?\s*,\s*(-?\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%(\s*,\s*(-?\d+|-?\d*.\d+))?\s*\)/.test(message.message)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
}
|
||||
/* STYLISH: hack end */
|
||||
|
||||
var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col;
|
||||
found.push({
|
||||
from: CodeMirror.Pos(startLine, startCol),
|
||||
to: CodeMirror.Pos(endLine, endCol),
|
||||
message: message.message,
|
||||
severity : message.type
|
||||
});
|
||||
}
|
||||
return found;
|
||||
});
|
||||
})(CodeMirror => {
|
||||
CodeMirror.registerHelper('lint', 'csslint', text => {
|
||||
const found = [];
|
||||
if (!window.CSSLint) {
|
||||
return found;
|
||||
}
|
||||
/* STYLUS: hack start (part 1) */
|
||||
return BG.chromeSync.getValue('editorCSSLintConfig').then(config => {
|
||||
// csslintDefaultConfig stored in csslint-config.js & loaded by edit/lint.js
|
||||
if (Object.keys(config || []).length === 0) {
|
||||
config = Object.assign({}, csslintDefaultConfig);
|
||||
}
|
||||
const results = CSSLint.verify(text, config);
|
||||
const messages = results.messages;
|
||||
const hslRegex = /hsla?\(\s*(-?\d+)%?\s*,\s*(-?\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%(\s*,\s*(-?\d+|-?\d*.\d+))?\s*\)/;
|
||||
let message = null;
|
||||
/* STYLUS: hack end */
|
||||
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
message = messages[i];
|
||||
|
||||
/* STYLUS: hack start (part 2) */
|
||||
if (message.type === 'warning') {
|
||||
// @font-face {font-family: 'Ampersand'; unicode-range: U+26;}
|
||||
if (message.message.indexOf('unicode-range') !== -1) {
|
||||
continue;
|
||||
} else if (
|
||||
// color: hsl(210, 100%, 2.2%); or color: hsla(210, 100%, 2.2%, 0.3);
|
||||
message.message.startsWith('Expected (<color>) but found \'hsl') &&
|
||||
hslRegex.test(message.message)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const startLine = message.line - 1;
|
||||
const endLine = message.line - 1;
|
||||
const startCol = message.col - 1;
|
||||
const endCol = message.col;
|
||||
/* STYLUS: hack end */
|
||||
|
||||
found.push({
|
||||
from: CodeMirror.Pos(startLine, startCol),
|
||||
to: CodeMirror.Pos(endLine, endCol),
|
||||
message: message.message + ` (${message.rule.id})`,
|
||||
severity : message.type
|
||||
});
|
||||
}
|
||||
return found;
|
||||
});
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper('lint', 'stylelint', text => {
|
||||
const found = [];
|
||||
window.stylelint = require('stylelint');
|
||||
if (window.stylelint) {
|
||||
return BG.chromeSync.getValue('editorStylelintConfig').then(rules => {
|
||||
// stylelintDefaultConfig stored in stylelint-config.js & loaded by edit/lint.js
|
||||
if (Object.keys(rules || []).length === 0) {
|
||||
rules = stylelintDefaultConfig.rules;
|
||||
}
|
||||
return stylelint.lint({
|
||||
code: text,
|
||||
config: {
|
||||
syntax: stylelintDefaultConfig.syntax,
|
||||
rules: rules
|
||||
}
|
||||
}).then(output => {
|
||||
const warnings = output.results.length ? output.results[0].warnings : [];
|
||||
const len = warnings.length;
|
||||
let warning;
|
||||
let message;
|
||||
if (len) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
warning = warnings[i];
|
||||
message = warning.text
|
||||
.replace('Unexpected ', '')
|
||||
.replace(/^./, function (firstLetter) {
|
||||
return firstLetter.toUpperCase();
|
||||
});
|
||||
found.push({
|
||||
from: CodeMirror.Pos(warning.line - 1, warning.column - 1),
|
||||
to: CodeMirror.Pos(warning.line - 1, warning.column),
|
||||
message,
|
||||
severity : warning.severity
|
||||
});
|
||||
}
|
||||
}
|
||||
return found;
|
||||
});
|
||||
});
|
||||
}
|
||||
return found;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
2. Apply our hacks unless supported natively
|
||||
(use git history for the file as this warning may be obsolete):
|
||||
|
||||
* 449a27cc Add CSSLint position sticky rule
|
||||
* d49e44dd CSS variables
|
||||
* 2e86c958 fire startdocument on {
|
||||
* bc63ecca support "i" in attribute selector
|
||||
* 2468784e fix crashing on unclosed calc() at eof
|
||||
* 3287b79f Support :any(), :-webkit-any(), :-moz-any()
|
|
@ -3714,7 +3714,7 @@ var Properties = module.exports = {
|
|||
"pitch-range" : 1,
|
||||
"play-during" : 1,
|
||||
"pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all",
|
||||
"position" : "static | relative | absolute | fixed",
|
||||
"position" : "static | relative | absolute | fixed | sticky",
|
||||
"presentation-level" : 1,
|
||||
"punctuation-trim" : 1,
|
||||
|
512
vendor-overwrites/lz-string/LZString-2xspeedup.js
Normal file
512
vendor-overwrites/lz-string/LZString-2xspeedup.js
Normal file
|
@ -0,0 +1,512 @@
|
|||
// ==UserScript==
|
||||
// @name LZString-2xspeedup
|
||||
// @description 2x speedup via ES6 Map and Set
|
||||
// @version 1.4.4
|
||||
// ==/UserScript==
|
||||
|
||||
// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
|
||||
// This work is free. You can redistribute it and/or modify it
|
||||
// under the terms of the WTFPL, Version 2
|
||||
// For more information see LICENSE.txt or http://www.wtfpl.net/
|
||||
//
|
||||
// For more information, the home page:
|
||||
// http://pieroxy.net/blog/pages/lz-string/testing.html
|
||||
//
|
||||
// LZ-based compression algorithm, version 1.4.4
|
||||
var LZString = (function() {
|
||||
|
||||
// private property
|
||||
var f = String.fromCharCode;
|
||||
var keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
var keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
|
||||
var baseReverseDic = {};
|
||||
|
||||
function getBaseValue(alphabet, character) {
|
||||
if (!baseReverseDic[alphabet]) {
|
||||
baseReverseDic[alphabet] = {};
|
||||
for (var i=0 ; i<alphabet.length ; i++) {
|
||||
baseReverseDic[alphabet][alphabet.charAt(i)] = i;
|
||||
}
|
||||
}
|
||||
return baseReverseDic[alphabet][character];
|
||||
}
|
||||
|
||||
var LZString = {
|
||||
compressToBase64 : function (input) {
|
||||
if (input == null) return "";
|
||||
var res = LZString._compress(input, 6, function(a){return keyStrBase64.charAt(a);});
|
||||
switch (res.length % 4) { // To produce valid Base64
|
||||
default: // When could this happen ?
|
||||
case 0 : return res;
|
||||
case 1 : return res+"===";
|
||||
case 2 : return res+"==";
|
||||
case 3 : return res+"=";
|
||||
}
|
||||
},
|
||||
|
||||
decompressFromBase64 : function (input) {
|
||||
if (input == null) return "";
|
||||
if (input == "") return null;
|
||||
return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrBase64, input.charAt(index)); });
|
||||
},
|
||||
|
||||
compressToUTF16 : function (input) {
|
||||
if (input == null) return "";
|
||||
return LZString._compress(input, 15, function(a){return f(a+32);}) + " ";
|
||||
},
|
||||
|
||||
decompressFromUTF16: function (compressed) {
|
||||
if (compressed == null) return "";
|
||||
if (compressed == "") return null;
|
||||
return LZString._decompress(compressed.length, 16384, function(index) { return compressed.charCodeAt(index) - 32; });
|
||||
},
|
||||
|
||||
//compress into uint8array (UCS-2 big endian format)
|
||||
compressToUint8Array: function (uncompressed) {
|
||||
var compressed = LZString.compress(uncompressed);
|
||||
var buf=new Uint8Array(compressed.length*2); // 2 bytes per character
|
||||
|
||||
for (var i=0, TotalLen=compressed.length; i<TotalLen; i++) {
|
||||
var current_value = compressed.charCodeAt(i);
|
||||
buf[i*2] = current_value >>> 8;
|
||||
buf[i*2+1] = current_value % 256;
|
||||
}
|
||||
return buf;
|
||||
},
|
||||
|
||||
//decompress from uint8array (UCS-2 big endian format)
|
||||
decompressFromUint8Array:function (compressed) {
|
||||
if (compressed===null || compressed===undefined){
|
||||
return LZString.decompress(compressed);
|
||||
} else {
|
||||
var buf=new Array(compressed.length/2); // 2 bytes per character
|
||||
for (var i=0, TotalLen=buf.length; i<TotalLen; i++) {
|
||||
buf[i]=compressed[i*2]*256+compressed[i*2+1];
|
||||
}
|
||||
|
||||
var result = [];
|
||||
buf.forEach(function (c) {
|
||||
result.push(f(c));
|
||||
});
|
||||
return LZString.decompress(result.join(''));
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
//compress into a string that is already URI encoded
|
||||
compressToEncodedURIComponent: function (input) {
|
||||
if (input == null) return "";
|
||||
return LZString._compress(input, 6, function(a){return keyStrUriSafe.charAt(a);});
|
||||
},
|
||||
|
||||
//decompress from an output of compressToEncodedURIComponent
|
||||
decompressFromEncodedURIComponent:function (input) {
|
||||
if (input == null) return "";
|
||||
if (input == "") return null;
|
||||
input = input.replace(/ /g, "+");
|
||||
return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrUriSafe, input.charAt(index)); });
|
||||
},
|
||||
|
||||
compress: function (uncompressed) {
|
||||
return LZString._compress(uncompressed, 16, function(a){return f(a);});
|
||||
},
|
||||
_compress: function (uncompressed, bitsPerChar, getCharFromInt) {
|
||||
if (uncompressed == null) return "";
|
||||
var i, value,
|
||||
context_dictionary= new Map(),
|
||||
context_dictionaryToCreate= new Set(),
|
||||
context_c="",
|
||||
context_wc="",
|
||||
context_w="",
|
||||
context_enlargeIn= 2, // Compensate for the first entry which should not count
|
||||
context_dictSize= 3,
|
||||
context_numBits= 2,
|
||||
context_data=[],
|
||||
context_data_val=0,
|
||||
context_data_position=0,
|
||||
ii;
|
||||
|
||||
for (ii = 0; ii < uncompressed.length; ii += 1) {
|
||||
context_c = uncompressed.charAt(ii);
|
||||
if (!context_dictionary.has(context_c)) {
|
||||
context_dictionary.set(context_c, context_dictSize++);
|
||||
context_dictionaryToCreate.add(context_c);
|
||||
}
|
||||
|
||||
context_wc = context_w + context_c;
|
||||
if (context_dictionary.has(context_wc)) {
|
||||
context_w = context_wc;
|
||||
} else {
|
||||
if (context_dictionaryToCreate.has(context_w)) {
|
||||
if (context_w.charCodeAt(0)<256) {
|
||||
for (i=0 ; i<context_numBits ; i++) {
|
||||
context_data_val = (context_data_val << 1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
}
|
||||
value = context_w.charCodeAt(0);
|
||||
for (i=0 ; i<8 ; i++) {
|
||||
context_data_val = (context_data_val << 1) | (value&1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
value = value >> 1;
|
||||
}
|
||||
} else {
|
||||
value = 1;
|
||||
for (i=0 ; i<context_numBits ; i++) {
|
||||
context_data_val = (context_data_val << 1) | value;
|
||||
if (context_data_position ==bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
value = 0;
|
||||
}
|
||||
value = context_w.charCodeAt(0);
|
||||
for (i=0 ; i<16 ; i++) {
|
||||
context_data_val = (context_data_val << 1) | (value&1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
value = value >> 1;
|
||||
}
|
||||
}
|
||||
context_enlargeIn--;
|
||||
if (context_enlargeIn == 0) {
|
||||
context_enlargeIn = Math.pow(2, context_numBits);
|
||||
context_numBits++;
|
||||
}
|
||||
context_dictionaryToCreate.delete(context_w);
|
||||
} else {
|
||||
value = context_dictionary.get(context_w);
|
||||
for (i=0 ; i<context_numBits ; i++) {
|
||||
context_data_val = (context_data_val << 1) | (value&1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
value = value >> 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
context_enlargeIn--;
|
||||
if (context_enlargeIn == 0) {
|
||||
context_enlargeIn = Math.pow(2, context_numBits);
|
||||
context_numBits++;
|
||||
}
|
||||
// Add wc to the dictionary.
|
||||
context_dictionary.set(context_wc, context_dictSize++);
|
||||
context_w = String(context_c);
|
||||
}
|
||||
}
|
||||
|
||||
// Output the code for w.
|
||||
if (context_w !== "") {
|
||||
if (context_dictionaryToCreate.has(context_w)) {
|
||||
if (context_w.charCodeAt(0)<256) {
|
||||
for (i=0 ; i<context_numBits ; i++) {
|
||||
context_data_val = (context_data_val << 1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
}
|
||||
value = context_w.charCodeAt(0);
|
||||
for (i=0 ; i<8 ; i++) {
|
||||
context_data_val = (context_data_val << 1) | (value&1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
value = value >> 1;
|
||||
}
|
||||
} else {
|
||||
value = 1;
|
||||
for (i=0 ; i<context_numBits ; i++) {
|
||||
context_data_val = (context_data_val << 1) | value;
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
value = 0;
|
||||
}
|
||||
value = context_w.charCodeAt(0);
|
||||
for (i=0 ; i<16 ; i++) {
|
||||
context_data_val = (context_data_val << 1) | (value&1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
value = value >> 1;
|
||||
}
|
||||
}
|
||||
context_enlargeIn--;
|
||||
if (context_enlargeIn == 0) {
|
||||
context_enlargeIn = Math.pow(2, context_numBits);
|
||||
context_numBits++;
|
||||
}
|
||||
context_dictionaryToCreate.delete(context_w);
|
||||
} else {
|
||||
value = context_dictionary.get(context_w);
|
||||
for (i=0 ; i<context_numBits ; i++) {
|
||||
context_data_val = (context_data_val << 1) | (value&1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
value = value >> 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
context_enlargeIn--;
|
||||
if (context_enlargeIn == 0) {
|
||||
context_enlargeIn = Math.pow(2, context_numBits);
|
||||
context_numBits++;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the end of the stream
|
||||
value = 2;
|
||||
for (i=0 ; i<context_numBits ; i++) {
|
||||
context_data_val = (context_data_val << 1) | (value&1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data_position = 0;
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
context_data_val = 0;
|
||||
} else {
|
||||
context_data_position++;
|
||||
}
|
||||
value = value >> 1;
|
||||
}
|
||||
|
||||
// Flush the last char
|
||||
while (true) {
|
||||
context_data_val = (context_data_val << 1);
|
||||
if (context_data_position == bitsPerChar-1) {
|
||||
context_data.push(getCharFromInt(context_data_val));
|
||||
break;
|
||||
}
|
||||
else context_data_position++;
|
||||
}
|
||||
return context_data.join('');
|
||||
},
|
||||
|
||||
decompress: function (compressed) {
|
||||
if (compressed == null) return "";
|
||||
if (compressed == "") return null;
|
||||
return LZString._decompress(compressed.length, 32768, function(index) { return compressed.charCodeAt(index); });
|
||||
},
|
||||
|
||||
_decompress: function (length, resetValue, getNextValue) {
|
||||
var dictionary = [],
|
||||
next,
|
||||
enlargeIn = 4,
|
||||
dictSize = 4,
|
||||
numBits = 3,
|
||||
entry = "",
|
||||
result = [],
|
||||
i,
|
||||
w,
|
||||
bits, resb, maxpower, power,
|
||||
c,
|
||||
data = {val:getNextValue(0), position:resetValue, index:1};
|
||||
|
||||
for (i = 0; i < 3; i += 1) {
|
||||
dictionary[i] = i;
|
||||
}
|
||||
|
||||
bits = 0;
|
||||
maxpower = Math.pow(2,2);
|
||||
power=1;
|
||||
while (power!=maxpower) {
|
||||
resb = data.val & data.position;
|
||||
data.position >>= 1;
|
||||
if (data.position == 0) {
|
||||
data.position = resetValue;
|
||||
data.val = getNextValue(data.index++);
|
||||
}
|
||||
bits |= (resb>0 ? 1 : 0) * power;
|
||||
power <<= 1;
|
||||
}
|
||||
|
||||
switch (next = bits) {
|
||||
case 0:
|
||||
bits = 0;
|
||||
maxpower = Math.pow(2,8);
|
||||
power=1;
|
||||
while (power!=maxpower) {
|
||||
resb = data.val & data.position;
|
||||
data.position >>= 1;
|
||||
if (data.position == 0) {
|
||||
data.position = resetValue;
|
||||
data.val = getNextValue(data.index++);
|
||||
}
|
||||
bits |= (resb>0 ? 1 : 0) * power;
|
||||
power <<= 1;
|
||||
}
|
||||
c = f(bits);
|
||||
break;
|
||||
case 1:
|
||||
bits = 0;
|
||||
maxpower = Math.pow(2,16);
|
||||
power=1;
|
||||
while (power!=maxpower) {
|
||||
resb = data.val & data.position;
|
||||
data.position >>= 1;
|
||||
if (data.position == 0) {
|
||||
data.position = resetValue;
|
||||
data.val = getNextValue(data.index++);
|
||||
}
|
||||
bits |= (resb>0 ? 1 : 0) * power;
|
||||
power <<= 1;
|
||||
}
|
||||
c = f(bits);
|
||||
break;
|
||||
case 2:
|
||||
return "";
|
||||
}
|
||||
dictionary[3] = c;
|
||||
w = c;
|
||||
result.push(c);
|
||||
while (true) {
|
||||
if (data.index > length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
bits = 0;
|
||||
maxpower = Math.pow(2,numBits);
|
||||
power=1;
|
||||
while (power!=maxpower) {
|
||||
resb = data.val & data.position;
|
||||
data.position >>= 1;
|
||||
if (data.position == 0) {
|
||||
data.position = resetValue;
|
||||
data.val = getNextValue(data.index++);
|
||||
}
|
||||
bits |= (resb>0 ? 1 : 0) * power;
|
||||
power <<= 1;
|
||||
}
|
||||
|
||||
switch (c = bits) {
|
||||
case 0:
|
||||
bits = 0;
|
||||
maxpower = Math.pow(2,8);
|
||||
power=1;
|
||||
while (power!=maxpower) {
|
||||
resb = data.val & data.position;
|
||||
data.position >>= 1;
|
||||
if (data.position == 0) {
|
||||
data.position = resetValue;
|
||||
data.val = getNextValue(data.index++);
|
||||
}
|
||||
bits |= (resb>0 ? 1 : 0) * power;
|
||||
power <<= 1;
|
||||
}
|
||||
|
||||
dictionary[dictSize++] = f(bits);
|
||||
c = dictSize-1;
|
||||
enlargeIn--;
|
||||
break;
|
||||
case 1:
|
||||
bits = 0;
|
||||
maxpower = Math.pow(2,16);
|
||||
power=1;
|
||||
while (power!=maxpower) {
|
||||
resb = data.val & data.position;
|
||||
data.position >>= 1;
|
||||
if (data.position == 0) {
|
||||
data.position = resetValue;
|
||||
data.val = getNextValue(data.index++);
|
||||
}
|
||||
bits |= (resb>0 ? 1 : 0) * power;
|
||||
power <<= 1;
|
||||
}
|
||||
dictionary[dictSize++] = f(bits);
|
||||
c = dictSize-1;
|
||||
enlargeIn--;
|
||||
break;
|
||||
case 2:
|
||||
return result.join('');
|
||||
}
|
||||
|
||||
if (enlargeIn == 0) {
|
||||
enlargeIn = Math.pow(2, numBits);
|
||||
numBits++;
|
||||
}
|
||||
|
||||
if (dictionary[c]) {
|
||||
entry = dictionary[c];
|
||||
} else {
|
||||
if (c === dictSize) {
|
||||
entry = w + w.charAt(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
result.push(entry);
|
||||
|
||||
// Add w+entry[0] to the dictionary.
|
||||
dictionary[dictSize++] = w + entry.charAt(0);
|
||||
enlargeIn--;
|
||||
|
||||
w = entry;
|
||||
|
||||
if (enlargeIn == 0) {
|
||||
enlargeIn = Math.pow(2, numBits);
|
||||
numBits++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
return LZString;
|
||||
})();
|
||||
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(function () { return LZString; });
|
||||
} else if( typeof module !== 'undefined' && module != null ) {
|
||||
module.exports = LZString
|
||||
} else if( typeof angular !== 'undefined' && angular != null ) {
|
||||
angular.module('LZString', [])
|
||||
.factory('LZString', function () {
|
||||
return LZString;
|
||||
});
|
||||
}
|
1675
vendor-overwrites/stylelint/stylelint-bundle.min.js
vendored
Normal file
1675
vendor-overwrites/stylelint/stylelint-bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
vendor-overwrites/stylelint/stylelint-mod.md
Normal file
1
vendor-overwrites/stylelint/stylelint-mod.md
Normal file
|
@ -0,0 +1 @@
|
|||
Stylelint bundle file from https://github.com/Mottie/stylelint/tree/mod - see the readme for details.
|
37
vendor/codemirror/addon/lint/json-lint.js
vendored
Normal file
37
vendor/codemirror/addon/lint/json-lint.js
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Depends on jsonlint.js from https://github.com/zaach/jsonlint
|
||||
|
||||
// declare global: jsonlint
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerHelper("lint", "json", function(text) {
|
||||
var found = [];
|
||||
if (!window.jsonlint) {
|
||||
if (window.console) {
|
||||
window.console.error("Error: window.jsonlint not defined, CodeMirror JSON linting cannot run.");
|
||||
}
|
||||
return found;
|
||||
}
|
||||
jsonlint.parseError = function(str, hash) {
|
||||
var loc = hash.loc;
|
||||
found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
|
||||
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
|
||||
message: str});
|
||||
};
|
||||
try { jsonlint.parse(text); }
|
||||
catch(e) {}
|
||||
return found;
|
||||
});
|
||||
|
||||
});
|
818
vendor/codemirror/mode/javascript/javascript.js
vendored
Normal file
818
vendor/codemirror/mode/javascript/javascript.js
vendored
Normal file
|
@ -0,0 +1,818 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function expressionAllowed(stream, state, backUp) {
|
||||
return /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
|
||||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var statementIndent = parserConfig.statementIndent;
|
||||
var jsonldMode = parserConfig.jsonld;
|
||||
var jsonMode = parserConfig.json || jsonldMode;
|
||||
var isTS = parserConfig.typescript;
|
||||
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
|
||||
|
||||
// Tokenizer
|
||||
|
||||
var keywords = function(){
|
||||
function kw(type) {return {type: type, style: "keyword"};}
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
|
||||
|
||||
var jsKeywords = {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
|
||||
"var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
"function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
|
||||
"this": kw("this"), "class": kw("class"), "super": kw("atom"),
|
||||
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
|
||||
"await": C
|
||||
};
|
||||
|
||||
// Extend the 'normal' keywords with the TypeScript language extensions
|
||||
if (isTS) {
|
||||
var type = {type: "variable", style: "type"};
|
||||
var tsKeywords = {
|
||||
// object-like things
|
||||
"interface": kw("class"),
|
||||
"implements": C,
|
||||
"namespace": C,
|
||||
"module": kw("module"),
|
||||
"enum": kw("module"),
|
||||
|
||||
// scope modifiers
|
||||
"public": kw("modifier"),
|
||||
"private": kw("modifier"),
|
||||
"protected": kw("modifier"),
|
||||
"abstract": kw("modifier"),
|
||||
|
||||
// types
|
||||
"string": type, "number": type, "boolean": type, "any": type
|
||||
};
|
||||
|
||||
for (var attr in tsKeywords) {
|
||||
jsKeywords[attr] = tsKeywords[attr];
|
||||
}
|
||||
}
|
||||
|
||||
return jsKeywords;
|
||||
}();
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
|
||||
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
|
||||
|
||||
function readRegexp(stream) {
|
||||
var escaped = false, next, inSet = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped) {
|
||||
if (next == "/" && !inSet) return;
|
||||
if (next == "[") inSet = true;
|
||||
else if (inSet && next == "]") inSet = false;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
}
|
||||
|
||||
// Used as scratch variables to communicate multiple values without
|
||||
// consing up tons of objects.
|
||||
var type, content;
|
||||
function ret(tp, style, cont) {
|
||||
type = tp; content = cont;
|
||||
return style;
|
||||
}
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
|
||||
return ret("number", "number");
|
||||
} else if (ch == "." && stream.match("..")) {
|
||||
return ret("spread", "meta");
|
||||
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
||||
return ret(ch);
|
||||
} else if (ch == "=" && stream.eat(">")) {
|
||||
return ret("=>", "operator");
|
||||
} else if (ch == "0" && stream.eat(/x/i)) {
|
||||
stream.eatWhile(/[\da-f]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/o/i)) {
|
||||
stream.eatWhile(/[0-7]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/b/i)) {
|
||||
stream.eatWhile(/[01]/i);
|
||||
return ret("number", "number");
|
||||
} else if (/\d/.test(ch)) {
|
||||
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
} else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
} else if (expressionAllowed(stream, state, 1)) {
|
||||
readRegexp(stream);
|
||||
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
|
||||
return ret("regexp", "string-2");
|
||||
} else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
}
|
||||
} else if (ch == "`") {
|
||||
state.tokenize = tokenQuasi;
|
||||
return tokenQuasi(stream, state);
|
||||
} else if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return ret("error", "error");
|
||||
} else if (isOperatorChar.test(ch)) {
|
||||
if (ch != ">" || !state.lexical || state.lexical.type != ">")
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else if (wordRE.test(ch)) {
|
||||
stream.eatWhile(wordRE);
|
||||
var word = stream.current()
|
||||
if (state.lastType != ".") {
|
||||
if (keywords.propertyIsEnumerable(word)) {
|
||||
var kw = keywords[word]
|
||||
return ret(kw.type, kw.style, word)
|
||||
}
|
||||
if (word == "async" && stream.match(/^\s*[\(\w]/, false))
|
||||
return ret("async", "keyword", word)
|
||||
}
|
||||
return ret("variable", "variable", word)
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next;
|
||||
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
|
||||
state.tokenize = tokenBase;
|
||||
return ret("jsonld-keyword", "meta");
|
||||
}
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) break;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (!escaped) state.tokenize = tokenBase;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
|
||||
function tokenQuasi(stream, state) {
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return ret("quasi", "string-2", stream.current());
|
||||
}
|
||||
|
||||
var brackets = "([{}])";
|
||||
// This is a crude lookahead trick to try and notice that we're
|
||||
// parsing the argument patterns for a fat-arrow function before we
|
||||
// actually hit the arrow token. It only works if the arrow is on
|
||||
// the same line as the arguments and there's no strange noise
|
||||
// (comments) in between. Fallback is to only notice when we hit the
|
||||
// arrow, and not declare the arguments as locals for the arrow
|
||||
// body.
|
||||
function findFatArrow(stream, state) {
|
||||
if (state.fatArrowAt) state.fatArrowAt = null;
|
||||
var arrow = stream.string.indexOf("=>", stream.start);
|
||||
if (arrow < 0) return;
|
||||
|
||||
if (isTS) { // Try to skip TypeScript return type declarations after the arguments
|
||||
var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
|
||||
if (m) arrow = m.index
|
||||
}
|
||||
|
||||
var depth = 0, sawSomething = false;
|
||||
for (var pos = arrow - 1; pos >= 0; --pos) {
|
||||
var ch = stream.string.charAt(pos);
|
||||
var bracket = brackets.indexOf(ch);
|
||||
if (bracket >= 0 && bracket < 3) {
|
||||
if (!depth) { ++pos; break; }
|
||||
if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
|
||||
} else if (bracket >= 3 && bracket < 6) {
|
||||
++depth;
|
||||
} else if (wordRE.test(ch)) {
|
||||
sawSomething = true;
|
||||
} else if (/["'\/]/.test(ch)) {
|
||||
return;
|
||||
} else if (sawSomething && !depth) {
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sawSomething && !depth) state.fatArrowAt = pos;
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
|
||||
|
||||
function JSLexical(indented, column, type, align, prev, info) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.prev = prev;
|
||||
this.info = info;
|
||||
if (align != null) this.align = align;
|
||||
}
|
||||
|
||||
function inScope(state, varname) {
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
for (var cx = state.context; cx; cx = cx.prev) {
|
||||
for (var v = cx.vars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
}
|
||||
}
|
||||
|
||||
function parseJS(state, style, type, content, stream) {
|
||||
var cc = state.cc;
|
||||
// Communicate our context to the combinators.
|
||||
// (Less wasteful than consing up a hundred closures on every call.)
|
||||
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
|
||||
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = true;
|
||||
|
||||
while(true) {
|
||||
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
|
||||
if (combinator(type, content)) {
|
||||
while(cc.length && cc[cc.length - 1].lex)
|
||||
cc.pop()();
|
||||
if (cx.marked) return cx.marked;
|
||||
if (type == "variable" && inScope(state, content)) return "variable-2";
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combinator utils
|
||||
|
||||
var cx = {state: null, column: null, marked: null, cc: null};
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
function register(varname) {
|
||||
function inList(list) {
|
||||
for (var v = list; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
return false;
|
||||
}
|
||||
var state = cx.state;
|
||||
cx.marked = "def";
|
||||
if (state.context) {
|
||||
if (inList(state.localVars)) return;
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
} else {
|
||||
if (inList(state.globalVars)) return;
|
||||
if (parserConfig.globalVars)
|
||||
state.globalVars = {name: varname, next: state.globalVars};
|
||||
}
|
||||
}
|
||||
|
||||
// Combinators
|
||||
|
||||
var defaultVars = {name: "this", next: {name: "arguments"}};
|
||||
function pushcontext() {
|
||||
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
|
||||
cx.state.localVars = defaultVars;
|
||||
}
|
||||
function popcontext() {
|
||||
cx.state.localVars = cx.state.context.vars;
|
||||
cx.state.context = cx.state.context.prev;
|
||||
}
|
||||
function pushlex(type, info) {
|
||||
var result = function() {
|
||||
var state = cx.state, indent = state.indented;
|
||||
if (state.lexical.type == "stat") indent = state.lexical.indented;
|
||||
else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
|
||||
indent = outer.indented;
|
||||
state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
|
||||
};
|
||||
result.lex = true;
|
||||
return result;
|
||||
}
|
||||
function poplex() {
|
||||
var state = cx.state;
|
||||
if (state.lexical.prev) {
|
||||
if (state.lexical.type == ")")
|
||||
state.indented = state.lexical.indented;
|
||||
state.lexical = state.lexical.prev;
|
||||
}
|
||||
}
|
||||
poplex.lex = true;
|
||||
|
||||
function expect(wanted) {
|
||||
function exp(type) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";") return pass();
|
||||
else return cont(exp);
|
||||
};
|
||||
return exp;
|
||||
}
|
||||
|
||||
function statement(type, value) {
|
||||
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "{") return cont(pushlex("}"), block, poplex);
|
||||
if (type == ";") return cont();
|
||||
if (type == "if") {
|
||||
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
|
||||
cx.state.cc.pop()();
|
||||
return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
|
||||
}
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
|
||||
if (type == "variable") {
|
||||
if (isTS && value == "type") {
|
||||
cx.marked = "keyword"
|
||||
return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
|
||||
} else {
|
||||
return cont(pushlex("stat"), maybelabel);
|
||||
}
|
||||
}
|
||||
if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"),
|
||||
block, poplex, poplex);
|
||||
if (type == "case") return cont(expression, expect(":"));
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
|
||||
statement, poplex, popcontext);
|
||||
if (type == "class") return cont(pushlex("form"), className, poplex);
|
||||
if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
|
||||
if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
|
||||
if (type == "module") return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
|
||||
if (type == "async") return cont(statement)
|
||||
if (value == "@") return cont(expression, statement)
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
return expressionInner(type, false);
|
||||
}
|
||||
function expressionNoComma(type) {
|
||||
return expressionInner(type, true);
|
||||
}
|
||||
function parenExpr(type) {
|
||||
if (type != "(") return pass()
|
||||
return cont(pushlex(")"), expression, expect(")"), poplex)
|
||||
}
|
||||
function expressionInner(type, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
var body = noComma ? arrowBodyNoComma : arrowBody;
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
|
||||
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
|
||||
}
|
||||
|
||||
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
|
||||
if (type == "function") return cont(functiondef, maybeop);
|
||||
if (type == "class") return cont(pushlex("form"), classExpression, poplex);
|
||||
if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
|
||||
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
|
||||
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
|
||||
if (type == "quasi") return pass(quasi, maybeop);
|
||||
if (type == "new") return cont(maybeTarget(noComma));
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expression);
|
||||
}
|
||||
function maybeexpressionNoComma(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expressionNoComma);
|
||||
}
|
||||
|
||||
function maybeoperatorComma(type, value) {
|
||||
if (type == ",") return cont(expression);
|
||||
return maybeoperatorNoComma(type, value, false);
|
||||
}
|
||||
function maybeoperatorNoComma(type, value, noComma) {
|
||||
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
|
||||
var expr = noComma == false ? expression : expressionNoComma;
|
||||
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value)) return cont(me);
|
||||
if (value == "?") return cont(expression, expect(":"), expr);
|
||||
return cont(expr);
|
||||
}
|
||||
if (type == "quasi") { return pass(quasi, me); }
|
||||
if (type == ";") return;
|
||||
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
|
||||
if (type == ".") return cont(property, me);
|
||||
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
|
||||
if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
|
||||
}
|
||||
function quasi(type, value) {
|
||||
if (type != "quasi") return pass();
|
||||
if (value.slice(value.length - 2) != "${") return cont(quasi);
|
||||
return cont(expression, continueQuasi);
|
||||
}
|
||||
function continueQuasi(type) {
|
||||
if (type == "}") {
|
||||
cx.marked = "string-2";
|
||||
cx.state.tokenize = tokenQuasi;
|
||||
return cont(quasi);
|
||||
}
|
||||
}
|
||||
function arrowBody(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expression);
|
||||
}
|
||||
function arrowBodyNoComma(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expressionNoComma);
|
||||
}
|
||||
function maybeTarget(noComma) {
|
||||
return function(type) {
|
||||
if (type == ".") return cont(noComma ? targetNoComma : target);
|
||||
else return pass(noComma ? expressionNoComma : expression);
|
||||
};
|
||||
}
|
||||
function target(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
|
||||
}
|
||||
function targetNoComma(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperatorComma, expect(";"), poplex);
|
||||
}
|
||||
function property(type) {
|
||||
if (type == "variable") {cx.marked = "property"; return cont();}
|
||||
}
|
||||
function objprop(type, value) {
|
||||
if (type == "async") {
|
||||
cx.marked = "property";
|
||||
return cont(objprop);
|
||||
} else if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
return cont(afterprop);
|
||||
} else if (type == "number" || type == "string") {
|
||||
cx.marked = jsonldMode ? "property" : (cx.style + " property");
|
||||
return cont(afterprop);
|
||||
} else if (type == "jsonld-keyword") {
|
||||
return cont(afterprop);
|
||||
} else if (type == "modifier") {
|
||||
return cont(objprop)
|
||||
} else if (type == "[") {
|
||||
return cont(expression, expect("]"), afterprop);
|
||||
} else if (type == "spread") {
|
||||
return cont(expression, afterprop);
|
||||
} else if (type == ":") {
|
||||
return pass(afterprop)
|
||||
}
|
||||
}
|
||||
function getterSetter(type) {
|
||||
if (type != "variable") return pass(afterprop);
|
||||
cx.marked = "property";
|
||||
return cont(functiondef);
|
||||
}
|
||||
function afterprop(type) {
|
||||
if (type == ":") return cont(expressionNoComma);
|
||||
if (type == "(") return pass(functiondef);
|
||||
}
|
||||
function commasep(what, end, sep) {
|
||||
function proceed(type, value) {
|
||||
if (sep ? sep.indexOf(type) > -1 : type == ",") {
|
||||
var lex = cx.state.lexical;
|
||||
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
|
||||
return cont(function(type, value) {
|
||||
if (type == end || value == end) return pass()
|
||||
return pass(what)
|
||||
}, proceed);
|
||||
}
|
||||
if (type == end || value == end) return cont();
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function(type, value) {
|
||||
if (type == end || value == end) return cont();
|
||||
return pass(what, proceed);
|
||||
};
|
||||
}
|
||||
function contCommasep(what, end, info) {
|
||||
for (var i = 3; i < arguments.length; i++)
|
||||
cx.cc.push(arguments[i]);
|
||||
return cont(pushlex(end, info), commasep(what, end), poplex);
|
||||
}
|
||||
function block(type) {
|
||||
if (type == "}") return cont();
|
||||
return pass(statement, block);
|
||||
}
|
||||
function maybetype(type, value) {
|
||||
if (isTS) {
|
||||
if (type == ":") return cont(typeexpr);
|
||||
if (value == "?") return cont(maybetype);
|
||||
}
|
||||
}
|
||||
function typeexpr(type) {
|
||||
if (type == "variable") {cx.marked = "type"; return cont(afterType);}
|
||||
if (type == "string" || type == "number" || type == "atom") return cont(afterType);
|
||||
if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
|
||||
if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
|
||||
}
|
||||
function maybeReturnType(type) {
|
||||
if (type == "=>") return cont(typeexpr)
|
||||
}
|
||||
function typeprop(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property"
|
||||
return cont(typeprop)
|
||||
} else if (value == "?") {
|
||||
return cont(typeprop)
|
||||
} else if (type == ":") {
|
||||
return cont(typeexpr)
|
||||
} else if (type == "[") {
|
||||
return cont(expression, maybetype, expect("]"), typeprop)
|
||||
}
|
||||
}
|
||||
function typearg(type) {
|
||||
if (type == "variable") return cont(typearg)
|
||||
else if (type == ":") return cont(typeexpr)
|
||||
}
|
||||
function afterType(type, value) {
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
|
||||
if (value == "|" || type == ".") return cont(typeexpr)
|
||||
if (type == "[") return cont(expect("]"), afterType)
|
||||
if (value == "extends") return cont(typeexpr)
|
||||
}
|
||||
function vardef() {
|
||||
return pass(pattern, maybetype, maybeAssign, vardefCont);
|
||||
}
|
||||
function pattern(type, value) {
|
||||
if (type == "modifier") return cont(pattern)
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "[") return contCommasep(pattern, "]");
|
||||
if (type == "{") return contCommasep(proppattern, "}");
|
||||
}
|
||||
function proppattern(type, value) {
|
||||
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
|
||||
register(value);
|
||||
return cont(maybeAssign);
|
||||
}
|
||||
if (type == "variable") cx.marked = "property";
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "}") return pass();
|
||||
return cont(expect(":"), pattern, maybeAssign);
|
||||
}
|
||||
function maybeAssign(_type, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
function vardefCont(type) {
|
||||
if (type == ",") return cont(vardef);
|
||||
}
|
||||
function maybeelse(type, value) {
|
||||
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
|
||||
}
|
||||
function forspec(type) {
|
||||
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
|
||||
}
|
||||
function forspec1(type) {
|
||||
if (type == "var") return cont(vardef, expect(";"), forspec2);
|
||||
if (type == ";") return cont(forspec2);
|
||||
if (type == "variable") return cont(formaybeinof);
|
||||
return pass(expression, expect(";"), forspec2);
|
||||
}
|
||||
function formaybeinof(_type, value) {
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return cont(maybeoperatorComma, forspec2);
|
||||
}
|
||||
function forspec2(type, value) {
|
||||
if (type == ";") return cont(forspec3);
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return pass(expression, expect(";"), forspec3);
|
||||
}
|
||||
function forspec3(type) {
|
||||
if (type != ")") cont(expression);
|
||||
}
|
||||
function functiondef(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
|
||||
if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
|
||||
}
|
||||
function funarg(type) {
|
||||
if (type == "spread") return cont(funarg);
|
||||
return pass(pattern, maybetype, maybeAssign);
|
||||
}
|
||||
function classExpression(type, value) {
|
||||
// Class expressions may have an optional name.
|
||||
if (type == "variable") return className(type, value);
|
||||
return classNameAfter(type, value);
|
||||
}
|
||||
function className(type, value) {
|
||||
if (type == "variable") {register(value); return cont(classNameAfter);}
|
||||
}
|
||||
function classNameAfter(type, value) {
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, classNameAfter)
|
||||
if (value == "extends" || value == "implements" || (isTS && type == ","))
|
||||
return cont(isTS ? typeexpr : expression, classNameAfter);
|
||||
if (type == "{") return cont(pushlex("}"), classBody, poplex);
|
||||
}
|
||||
function classBody(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
if ((value == "async" || value == "static" || value == "get" || value == "set" ||
|
||||
(isTS && (value == "public" || value == "private" || value == "protected" || value == "readonly" || value == "abstract"))) &&
|
||||
cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false)) {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
cx.marked = "property";
|
||||
return cont(isTS ? classfield : functiondef, classBody);
|
||||
}
|
||||
if (type == "[")
|
||||
return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
|
||||
if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (type == ";") return cont(classBody);
|
||||
if (type == "}") return cont();
|
||||
if (value == "@") return cont(expression, classBody)
|
||||
}
|
||||
function classfield(type, value) {
|
||||
if (value == "?") return cont(classfield)
|
||||
if (type == ":") return cont(typeexpr, maybeAssign)
|
||||
if (value == "=") return cont(expressionNoComma)
|
||||
return pass(functiondef)
|
||||
}
|
||||
function afterExport(type, value) {
|
||||
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
|
||||
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
|
||||
if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
|
||||
return pass(statement);
|
||||
}
|
||||
function exportField(type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
|
||||
if (type == "variable") return pass(expressionNoComma, exportField);
|
||||
}
|
||||
function afterImport(type) {
|
||||
if (type == "string") return cont();
|
||||
return pass(importSpec, maybeMoreImports, maybeFrom);
|
||||
}
|
||||
function importSpec(type, value) {
|
||||
if (type == "{") return contCommasep(importSpec, "}");
|
||||
if (type == "variable") register(value);
|
||||
if (value == "*") cx.marked = "keyword";
|
||||
return cont(maybeAs);
|
||||
}
|
||||
function maybeMoreImports(type) {
|
||||
if (type == ",") return cont(importSpec, maybeMoreImports)
|
||||
}
|
||||
function maybeAs(_type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
|
||||
}
|
||||
function maybeFrom(_type, value) {
|
||||
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
|
||||
}
|
||||
function arrayLiteral(type) {
|
||||
if (type == "]") return cont();
|
||||
return pass(commasep(expressionNoComma, "]"));
|
||||
}
|
||||
|
||||
function isContinuedStatement(state, textAfter) {
|
||||
return state.lastType == "operator" || state.lastType == "," ||
|
||||
isOperatorChar.test(textAfter.charAt(0)) ||
|
||||
/[,.]/.test(textAfter.charAt(0));
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
var state = {
|
||||
tokenize: tokenBase,
|
||||
lastType: "sof",
|
||||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: parserConfig.localVars,
|
||||
context: parserConfig.localVars && {vars: parserConfig.localVars},
|
||||
indented: basecolumn || 0
|
||||
};
|
||||
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
|
||||
state.globalVars = parserConfig.globalVars;
|
||||
return state;
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = false;
|
||||
state.indented = stream.indentation();
|
||||
findFatArrow(stream, state);
|
||||
}
|
||||
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
|
||||
return parseJS(state, style, type, content, stream);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize == tokenComment) return CodeMirror.Pass;
|
||||
if (state.tokenize != tokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
|
||||
// Kludge to prevent 'maybelse' from blocking lexical scope pops
|
||||
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
|
||||
var c = state.cc[i];
|
||||
if (c == poplex) lexical = lexical.prev;
|
||||
else if (c != maybeelse) break;
|
||||
}
|
||||
while ((lexical.type == "stat" || lexical.type == "form") &&
|
||||
(firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
|
||||
(top == maybeoperatorComma || top == maybeoperatorNoComma) &&
|
||||
!/^[,\.=+\-*:?[\(]/.test(textAfter))))
|
||||
lexical = lexical.prev;
|
||||
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
|
||||
lexical = lexical.prev;
|
||||
var type = lexical.type, closing = firstChar == type;
|
||||
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "form") return lexical.indented + indentUnit;
|
||||
else if (type == "stat")
|
||||
return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
|
||||
else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
|
||||
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
|
||||
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
|
||||
else return lexical.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
|
||||
blockCommentStart: jsonMode ? null : "/*",
|
||||
blockCommentEnd: jsonMode ? null : "*/",
|
||||
lineComment: jsonMode ? null : "//",
|
||||
fold: "brace",
|
||||
closeBrackets: "()[]{}''\"\"``",
|
||||
|
||||
helperType: jsonMode ? "json" : "javascript",
|
||||
jsonldMode: jsonldMode,
|
||||
jsonMode: jsonMode,
|
||||
|
||||
expressionAllowed: expressionAllowed,
|
||||
skipExpression: function(state) {
|
||||
var top = state.cc[state.cc.length - 1]
|
||||
if (top == expression || top == expressionNoComma) state.cc.pop()
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
|
||||
|
||||
CodeMirror.defineMIME("text/javascript", "javascript");
|
||||
CodeMirror.defineMIME("text/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/x-javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
|
||||
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
|
||||
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
|
||||
|
||||
});
|
432
vendor/jsonlint/jsonlint.js
vendored
Normal file
432
vendor/jsonlint/jsonlint.js
vendored
Normal file
|
@ -0,0 +1,432 @@
|
|||
/* Jison generated parser */
|
||||
var jsonlint = (function(){
|
||||
var parser = {trace: function trace() { },
|
||||
yy: {},
|
||||
symbols_: {"error":2,"JSONString":3,"STRING":4,"JSONNumber":5,"NUMBER":6,"JSONNullLiteral":7,"NULL":8,"JSONBooleanLiteral":9,"TRUE":10,"FALSE":11,"JSONText":12,"JSONValue":13,"EOF":14,"JSONObject":15,"JSONArray":16,"{":17,"}":18,"JSONMemberList":19,"JSONMember":20,":":21,",":22,"[":23,"]":24,"JSONElementList":25,"$accept":0,"$end":1},
|
||||
terminals_: {2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"},
|
||||
productions_: [0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]],
|
||||
performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
|
||||
|
||||
var $0 = $$.length - 1;
|
||||
switch (yystate) {
|
||||
case 1: // replace escaped characters with actual character
|
||||
this.$ = yytext.replace(/\\(\\|")/g, "$"+"1")
|
||||
.replace(/\\n/g,'\n')
|
||||
.replace(/\\r/g,'\r')
|
||||
.replace(/\\t/g,'\t')
|
||||
.replace(/\\v/g,'\v')
|
||||
.replace(/\\f/g,'\f')
|
||||
.replace(/\\b/g,'\b');
|
||||
|
||||
break;
|
||||
case 2:this.$ = Number(yytext);
|
||||
break;
|
||||
case 3:this.$ = null;
|
||||
break;
|
||||
case 4:this.$ = true;
|
||||
break;
|
||||
case 5:this.$ = false;
|
||||
break;
|
||||
case 6:return this.$ = $$[$0-1];
|
||||
break;
|
||||
case 13:this.$ = {};
|
||||
break;
|
||||
case 14:this.$ = $$[$0-1];
|
||||
break;
|
||||
case 15:this.$ = [$$[$0-2], $$[$0]];
|
||||
break;
|
||||
case 16:this.$ = {}; this.$[$$[$0][0]] = $$[$0][1];
|
||||
break;
|
||||
case 17:this.$ = $$[$0-2]; $$[$0-2][$$[$0][0]] = $$[$0][1];
|
||||
break;
|
||||
case 18:this.$ = [];
|
||||
break;
|
||||
case 19:this.$ = $$[$0-1];
|
||||
break;
|
||||
case 20:this.$ = [$$[$0]];
|
||||
break;
|
||||
case 21:this.$ = $$[$0-2]; $$[$0-2].push($$[$0]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
table: [{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],12:1,13:2,15:7,16:8,17:[1,14],23:[1,15]},{1:[3]},{14:[1,16]},{14:[2,7],18:[2,7],22:[2,7],24:[2,7]},{14:[2,8],18:[2,8],22:[2,8],24:[2,8]},{14:[2,9],18:[2,9],22:[2,9],24:[2,9]},{14:[2,10],18:[2,10],22:[2,10],24:[2,10]},{14:[2,11],18:[2,11],22:[2,11],24:[2,11]},{14:[2,12],18:[2,12],22:[2,12],24:[2,12]},{14:[2,3],18:[2,3],22:[2,3],24:[2,3]},{14:[2,4],18:[2,4],22:[2,4],24:[2,4]},{14:[2,5],18:[2,5],22:[2,5],24:[2,5]},{14:[2,1],18:[2,1],21:[2,1],22:[2,1],24:[2,1]},{14:[2,2],18:[2,2],22:[2,2],24:[2,2]},{3:20,4:[1,12],18:[1,17],19:18,20:19},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:23,15:7,16:8,17:[1,14],23:[1,15],24:[1,21],25:22},{1:[2,6]},{14:[2,13],18:[2,13],22:[2,13],24:[2,13]},{18:[1,24],22:[1,25]},{18:[2,16],22:[2,16]},{21:[1,26]},{14:[2,18],18:[2,18],22:[2,18],24:[2,18]},{22:[1,28],24:[1,27]},{22:[2,20],24:[2,20]},{14:[2,14],18:[2,14],22:[2,14],24:[2,14]},{3:20,4:[1,12],20:29},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:30,15:7,16:8,17:[1,14],23:[1,15]},{14:[2,19],18:[2,19],22:[2,19],24:[2,19]},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:31,15:7,16:8,17:[1,14],23:[1,15]},{18:[2,17],22:[2,17]},{18:[2,15],22:[2,15]},{22:[2,21],24:[2,21]}],
|
||||
defaultActions: {16:[2,6]},
|
||||
parseError: function parseError(str, hash) {
|
||||
throw new Error(str);
|
||||
},
|
||||
parse: function parse(input) {
|
||||
var self = this,
|
||||
stack = [0],
|
||||
vstack = [null], // semantic value stack
|
||||
lstack = [], // location stack
|
||||
table = this.table,
|
||||
yytext = '',
|
||||
yylineno = 0,
|
||||
yyleng = 0,
|
||||
recovering = 0,
|
||||
TERROR = 2,
|
||||
EOF = 1;
|
||||
|
||||
//this.reductionCount = this.shiftCount = 0;
|
||||
|
||||
this.lexer.setInput(input);
|
||||
this.lexer.yy = this.yy;
|
||||
this.yy.lexer = this.lexer;
|
||||
if (typeof this.lexer.yylloc == 'undefined')
|
||||
this.lexer.yylloc = {};
|
||||
var yyloc = this.lexer.yylloc;
|
||||
lstack.push(yyloc);
|
||||
|
||||
if (typeof this.yy.parseError === 'function')
|
||||
this.parseError = this.yy.parseError;
|
||||
|
||||
function popStack (n) {
|
||||
stack.length = stack.length - 2*n;
|
||||
vstack.length = vstack.length - n;
|
||||
lstack.length = lstack.length - n;
|
||||
}
|
||||
|
||||
function lex() {
|
||||
var token;
|
||||
token = self.lexer.lex() || 1; // $end = 1
|
||||
// if token isn't its numeric value, convert
|
||||
if (typeof token !== 'number') {
|
||||
token = self.symbols_[token] || token;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
|
||||
while (true) {
|
||||
// retreive state number from top of stack
|
||||
state = stack[stack.length-1];
|
||||
|
||||
// use default actions if available
|
||||
if (this.defaultActions[state]) {
|
||||
action = this.defaultActions[state];
|
||||
} else {
|
||||
if (symbol == null)
|
||||
symbol = lex();
|
||||
// read action for current state and first input
|
||||
action = table[state] && table[state][symbol];
|
||||
}
|
||||
|
||||
// handle parse error
|
||||
_handle_error:
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
|
||||
if (!recovering) {
|
||||
// Report error
|
||||
expected = [];
|
||||
for (p in table[state]) if (this.terminals_[p] && p > 2) {
|
||||
expected.push("'"+this.terminals_[p]+"'");
|
||||
}
|
||||
var errStr = '';
|
||||
if (this.lexer.showPosition) {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";
|
||||
} else {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
|
||||
(symbol == 1 /*EOF*/ ? "end of input" :
|
||||
("'"+(this.terminals_[symbol] || symbol)+"'"));
|
||||
}
|
||||
this.parseError(errStr,
|
||||
{text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
|
||||
}
|
||||
|
||||
// just recovered from another error
|
||||
if (recovering == 3) {
|
||||
if (symbol == EOF) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
|
||||
// discard current lookahead and grab another
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
yyloc = this.lexer.yylloc;
|
||||
symbol = lex();
|
||||
}
|
||||
|
||||
// try to recover from error
|
||||
while (1) {
|
||||
// check for error recovery rule in this state
|
||||
if ((TERROR.toString()) in table[state]) {
|
||||
break;
|
||||
}
|
||||
if (state == 0) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
popStack(1);
|
||||
state = stack[stack.length-1];
|
||||
}
|
||||
|
||||
preErrorSymbol = symbol; // save the lookahead token
|
||||
symbol = TERROR; // insert generic error symbol as new lookahead
|
||||
state = stack[stack.length-1];
|
||||
action = table[state] && table[state][TERROR];
|
||||
recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
|
||||
}
|
||||
|
||||
// this shouldn't happen, unless resolve defaults are off
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
|
||||
}
|
||||
|
||||
switch (action[0]) {
|
||||
|
||||
case 1: // shift
|
||||
//this.shiftCount++;
|
||||
|
||||
stack.push(symbol);
|
||||
vstack.push(this.lexer.yytext);
|
||||
lstack.push(this.lexer.yylloc);
|
||||
stack.push(action[1]); // push state
|
||||
symbol = null;
|
||||
if (!preErrorSymbol) { // normal execution/no error
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
yyloc = this.lexer.yylloc;
|
||||
if (recovering > 0)
|
||||
recovering--;
|
||||
} else { // error just occurred, resume old lookahead f/ before error
|
||||
symbol = preErrorSymbol;
|
||||
preErrorSymbol = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // reduce
|
||||
//this.reductionCount++;
|
||||
|
||||
len = this.productions_[action[1]][1];
|
||||
|
||||
// perform semantic action
|
||||
yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
|
||||
// default location, uses first token for firsts, last for lasts
|
||||
yyval._$ = {
|
||||
first_line: lstack[lstack.length-(len||1)].first_line,
|
||||
last_line: lstack[lstack.length-1].last_line,
|
||||
first_column: lstack[lstack.length-(len||1)].first_column,
|
||||
last_column: lstack[lstack.length-1].last_column
|
||||
};
|
||||
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
|
||||
|
||||
if (typeof r !== 'undefined') {
|
||||
return r;
|
||||
}
|
||||
|
||||
// pop off stack
|
||||
if (len) {
|
||||
stack = stack.slice(0,-1*len*2);
|
||||
vstack = vstack.slice(0, -1*len);
|
||||
lstack = lstack.slice(0, -1*len);
|
||||
}
|
||||
|
||||
stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
|
||||
vstack.push(yyval.$);
|
||||
lstack.push(yyval._$);
|
||||
// goto new state = table[STATE][NONTERMINAL]
|
||||
newState = table[stack[stack.length-2]][stack[stack.length-1]];
|
||||
stack.push(newState);
|
||||
break;
|
||||
|
||||
case 3: // accept
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}};
|
||||
/* Jison generated lexer */
|
||||
var lexer = (function(){
|
||||
var lexer = ({EOF:1,
|
||||
parseError:function parseError(str, hash) {
|
||||
if (this.yy.parseError) {
|
||||
this.yy.parseError(str, hash);
|
||||
} else {
|
||||
throw new Error(str);
|
||||
}
|
||||
},
|
||||
setInput:function (input) {
|
||||
this._input = input;
|
||||
this._more = this._less = this.done = false;
|
||||
this.yylineno = this.yyleng = 0;
|
||||
this.yytext = this.matched = this.match = '';
|
||||
this.conditionStack = ['INITIAL'];
|
||||
this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
|
||||
return this;
|
||||
},
|
||||
input:function () {
|
||||
var ch = this._input[0];
|
||||
this.yytext+=ch;
|
||||
this.yyleng++;
|
||||
this.match+=ch;
|
||||
this.matched+=ch;
|
||||
var lines = ch.match(/\n/);
|
||||
if (lines) this.yylineno++;
|
||||
this._input = this._input.slice(1);
|
||||
return ch;
|
||||
},
|
||||
unput:function (ch) {
|
||||
this._input = ch + this._input;
|
||||
return this;
|
||||
},
|
||||
more:function () {
|
||||
this._more = true;
|
||||
return this;
|
||||
},
|
||||
less:function (n) {
|
||||
this._input = this.match.slice(n) + this._input;
|
||||
},
|
||||
pastInput:function () {
|
||||
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
||||
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
|
||||
},
|
||||
upcomingInput:function () {
|
||||
var next = this.match;
|
||||
if (next.length < 20) {
|
||||
next += this._input.substr(0, 20-next.length);
|
||||
}
|
||||
return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
|
||||
},
|
||||
showPosition:function () {
|
||||
var pre = this.pastInput();
|
||||
var c = new Array(pre.length + 1).join("-");
|
||||
return pre + this.upcomingInput() + "\n" + c+"^";
|
||||
},
|
||||
next:function () {
|
||||
if (this.done) {
|
||||
return this.EOF;
|
||||
}
|
||||
if (!this._input) this.done = true;
|
||||
|
||||
var token,
|
||||
match,
|
||||
tempMatch,
|
||||
index,
|
||||
col,
|
||||
lines;
|
||||
if (!this._more) {
|
||||
this.yytext = '';
|
||||
this.match = '';
|
||||
}
|
||||
var rules = this._currentRules();
|
||||
for (var i=0;i < rules.length; i++) {
|
||||
tempMatch = this._input.match(this.rules[rules[i]]);
|
||||
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
|
||||
match = tempMatch;
|
||||
index = i;
|
||||
if (!this.options.flex) break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
lines = match[0].match(/\n.*/g);
|
||||
if (lines) this.yylineno += lines.length;
|
||||
this.yylloc = {first_line: this.yylloc.last_line,
|
||||
last_line: this.yylineno+1,
|
||||
first_column: this.yylloc.last_column,
|
||||
last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
|
||||
this.yytext += match[0];
|
||||
this.match += match[0];
|
||||
this.yyleng = this.yytext.length;
|
||||
this._more = false;
|
||||
this._input = this._input.slice(match[0].length);
|
||||
this.matched += match[0];
|
||||
token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]);
|
||||
if (this.done && this._input) this.done = false;
|
||||
if (token) return token;
|
||||
else return;
|
||||
}
|
||||
if (this._input === "") {
|
||||
return this.EOF;
|
||||
} else {
|
||||
this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
|
||||
{text: "", token: null, line: this.yylineno});
|
||||
}
|
||||
},
|
||||
lex:function lex() {
|
||||
var r = this.next();
|
||||
if (typeof r !== 'undefined') {
|
||||
return r;
|
||||
} else {
|
||||
return this.lex();
|
||||
}
|
||||
},
|
||||
begin:function begin(condition) {
|
||||
this.conditionStack.push(condition);
|
||||
},
|
||||
popState:function popState() {
|
||||
return this.conditionStack.pop();
|
||||
},
|
||||
_currentRules:function _currentRules() {
|
||||
return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
|
||||
},
|
||||
topState:function () {
|
||||
return this.conditionStack[this.conditionStack.length-2];
|
||||
},
|
||||
pushState:function begin(condition) {
|
||||
this.begin(condition);
|
||||
}});
|
||||
lexer.options = {};
|
||||
lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
|
||||
|
||||
var YYSTATE=YY_START
|
||||
switch($avoiding_name_collisions) {
|
||||
case 0:/* skip whitespace */
|
||||
break;
|
||||
case 1:return 6
|
||||
break;
|
||||
case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4
|
||||
break;
|
||||
case 3:return 17
|
||||
break;
|
||||
case 4:return 18
|
||||
break;
|
||||
case 5:return 23
|
||||
break;
|
||||
case 6:return 24
|
||||
break;
|
||||
case 7:return 22
|
||||
break;
|
||||
case 8:return 21
|
||||
break;
|
||||
case 9:return 10
|
||||
break;
|
||||
case 10:return 11
|
||||
break;
|
||||
case 11:return 8
|
||||
break;
|
||||
case 12:return 14
|
||||
break;
|
||||
case 13:return 'INVALID'
|
||||
break;
|
||||
}
|
||||
};
|
||||
lexer.rules = [/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/];
|
||||
lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}};
|
||||
|
||||
|
||||
;
|
||||
return lexer;})()
|
||||
parser.lexer = lexer;
|
||||
return parser;
|
||||
})();
|
||||
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
|
||||
exports.parser = jsonlint;
|
||||
exports.parse = function () { return jsonlint.parse.apply(jsonlint, arguments); }
|
||||
exports.main = function commonjsMain(args) {
|
||||
if (!args[1])
|
||||
throw new Error('Usage: '+args[0]+' FILE');
|
||||
if (typeof process !== 'undefined') {
|
||||
var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8");
|
||||
} else {
|
||||
var cwd = require("file").path(require("file").cwd());
|
||||
var source = cwd.join(args[1]).read({charset: "utf-8"});
|
||||
}
|
||||
return exports.parser.parse(source);
|
||||
}
|
||||
if (typeof module !== 'undefined' && require.main === module) {
|
||||
exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user