Skip to content

Commit

Permalink
feat: implement theme-based dynamic styles for Code Issue Panel [IDE-…
Browse files Browse the repository at this point in the history
…250] (#514)

* feat: implement theme-based dynamic styles for Code Issue Panel

- Dynamically sets CSS properties via `browser.executeJavaScript` based on the current IDE theme (dark or light).
- Visual elements rendered from the Language Server, such as text color, background color,
  link color, and other UI components, are consistent with the user's theme preference.

Related: snyk/snyk-ls#491 where support for dynamic dark and light themes was added.

* refactor: optimise JS initialisation and event handling in JBCefBrowser

- Use event delegation for the `.data-flow-clickable-row` elements. This change reduces the
  number of event listeners attached to the DOM by binding a single listener on
  the document rather than individual listeners on each element.
- Prevent redefinition of the `openFileQuery` function initialising just once per page load.

* feat: support Dark, Light and Darcula themes

* refactor: apply styles in a single iteration

* chore: update README

* fix: remove unnecessary file
  • Loading branch information
cat2608 authored Apr 22, 2024
1 parent eefaa7e commit 586082c
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Snyk Security Changelog

## [2.7.16]
### Added
- Implemented dynamic theme style changes for the Code Issue Panel via the Language Server. It adjusts CSS properties based on the current IDE theme settings to enhance visual consistency across different themes. See related PR: [snyk-ls#491](https://github.com/snyk/snyk-ls/pull/491).

## [2.7.15]
### Fixed
- Re-enable scan results when re-enabling different scan types
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.snyk.plugin.ui.jcef

import com.intellij.openapi.application.ApplicationManager
import com.intellij.ui.jcef.JBCefBrowser
import com.intellij.openapi.editor.colors.EditorColorsManager
import com.intellij.ui.jcef.JBCefBrowserBase
import com.intellij.ui.jcef.JBCefJSQuery
import io.snyk.plugin.getDocument
Expand All @@ -15,6 +15,10 @@ class OpenFileLoadHandlerGenerator(snykCodeFile: SnykCodeFile) {
private val project = snykCodeFile.project
private val virtualFile = snykCodeFile.virtualFile

companion object {
val darculaRegex = Regex(".*d(ar|ra)cula.*", RegexOption.IGNORE_CASE)
}

fun openFile(value: String): JBCefJSQuery.Response {
val values = value.replace("\n", "").split(":")
val startLine = values[1].toInt()
Expand All @@ -35,32 +39,78 @@ class OpenFileLoadHandlerGenerator(snykCodeFile: SnykCodeFile) {
return JBCefJSQuery.Response("success")
}

fun isDarcula(): Boolean {
val scheme = EditorColorsManager.getInstance().globalScheme
return darculaRegex.containsMatchIn(scheme.name)
}

fun generate(jbCefBrowser: JBCefBrowserBase): CefLoadHandlerAdapter {
val openFileQuery = JBCefJSQuery.create(jbCefBrowser)
openFileQuery.addHandler { openFile(it) }

return object : CefLoadHandlerAdapter() {
override fun onLoadEnd(browser: CefBrowser, frame: CefFrame, httpStatusCode: Int) {
if (frame.isMain) {
browser.executeJavaScript(
"window.openFileQuery = function(value) {" +
openFileQuery.inject("value") +
"};",
browser.url, 0
);
val script = """
(function() {
if (window.openFileQuery) {
return;
}
window.openFileQuery = function(value) { ${openFileQuery.inject("value")} };
// Attach a single event listener to the document
document.addEventListener('click', function(e) {
// Find the nearest ancestor
var target = e.target.closest('.data-flow-clickable-row');
if (target) {
e.preventDefault();
window.openFileQuery(target.getAttribute("file-path") + ":" +
target.getAttribute("start-line") + ":" +
target.getAttribute("end-line") + ":" +
target.getAttribute("start-character") + ":" +
target.getAttribute("end-character"));
}
});
})();
"""
browser.executeJavaScript(script, browser.url, 0)
val colorTheme = if (EditorColorsManager.getInstance().isDarkEditor) "dark" else "light"
val isDarculaTheme = isDarcula()
val themeScript = """
(function(){
if (window.themeApplied) {
return;
}
window.themeApplied = true;
const style = getComputedStyle(document.documentElement);
const properties = [
'--text-color',
'--background-color',
'--link-color',
'--info-text-color',
'--disabled-text-color',
'--selected-text-color',
'--error-text-color',
'--data-flow-file-color',
'--data-flow-body-color',
'--example-line-added-color',
'--example-line-removed-color',
'--tabs-bottom-color',
'--tab-item-color',
'--tab-item-hover-color',
'--tab-item-icon-color',
'--scrollbar-thumb-color',
'--scrollbar-color',
]
properties.forEach(p => document.documentElement.style.setProperty(p, style.getPropertyValue(p + "-" + "${colorTheme}")))
browser.executeJavaScript(
if (${isDarculaTheme}) {
document.documentElement.style.setProperty('--data-flow-body-color', style.getPropertyValue('--data-flow-body-color-darcula'));
document.documentElement.style.setProperty('--example-line-added-color', style.getPropertyValue('--example-line-added-color-darcula'));
document.documentElement.style.setProperty('--example-line-removed-color', style.getPropertyValue('--example-line-removed-color-darcula'));
}
})();
"""
const dataFlowFilePaths = document.getElementsByClassName('data-flow-clickable-row')
for (let i = 0; i < dataFlowFilePaths.length; i++) {
const dataFlowFilePath = dataFlowFilePaths[i]
dataFlowFilePath.addEventListener('click', function (e) {
e.preventDefault()
window.openFileQuery(dataFlowFilePath.getAttribute("file-path")+":"+dataFlowFilePath.getAttribute("start-line")+":"+dataFlowFilePath.getAttribute("end-line")+":"+dataFlowFilePath.getAttribute("start-character")+":"+dataFlowFilePath.getAttribute("end-character"));
});
}""",
browser.url, 0
);
browser.executeJavaScript(themeScript, browser.url, 0)
}
}
}
Expand Down

0 comments on commit 586082c

Please sign in to comment.