Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agreement redirect #76

Merged
merged 5 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ import kotlinx.serialization.Serializable
*/

@Serializable
data class Agreement(val text: String, val required: Boolean = true)
data class Agreement(val text: String, val required: Boolean = true, val openLinkInDefaultBrowser: Boolean = true)
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import org.jetbrains.research.tasktracker.tracking.fileEditor.FileEditorTracker
import org.jetbrains.research.tasktracker.tracking.toolWindow.ToolWindowTracker
import org.jetbrains.research.tasktracker.tracking.webcam.WebCamTracker
import org.jetbrains.research.tasktracker.tracking.webcam.collectAllDevices
import org.jetbrains.research.tasktracker.ui.main.panel.models.ButtonState
import org.jetbrains.research.tasktracker.ui.main.panel.models.LinkType
import org.jetbrains.research.tasktracker.ui.main.panel.panelStates.agreementAcceptance
import org.jetbrains.research.tasktracker.ui.main.panel.storage.GlobalPluginStorage
import org.jetbrains.research.tasktracker.ui.main.panel.template.HtmlTemplate
Expand All @@ -32,7 +34,6 @@ import org.jetbrains.research.tasktracker.util.UIBundle
import java.awt.BorderLayout
import java.awt.FlowLayout
import java.awt.event.ActionListener
import javax.swing.JButton

/**
* The class is intended to manage JCEF and Swing components simultaneously,
Expand Down Expand Up @@ -66,6 +67,7 @@ class MainPluginPanelFactory : ToolWindowFactory {
add(buttonPanel, BorderLayout.SOUTH)
}
toolWindow.component.add(panel)
listenRedirection()
}

override fun isApplicable(project: Project) = super.isApplicable(project) && JBCefApp.isSupported()
Expand Down Expand Up @@ -144,25 +146,30 @@ class MainPluginPanelFactory : ToolWindowFactory {
}
}

/**
* Opening file in editor by html link.
*/
fun listenFileRedirection(task: Task) {
mainWindow.executeJavascript(
"""
const files = document.getElementsByClassName('file');
for (const file of files) {
file.addEventListener('click', function(event) {
event.preventDefault();
})
file.onclick = load_file
}
function load_file (){
file_id = this.getAttribute('data-value');

""",
"}",
"file_id"
) {
mainWindow.jslinkProcess(LinkType.FILE) {
focusOnfFileById(task, it)
null
}
}

/**
* Redirecting to external websites in JCEF.
*/
private fun listenRedirection() {
mainWindow.jslinkProcess(LinkType.JCEF) {
val previousBackState = backButton.getState()
val previousNextState = nextButton.getState()
nextButton.changeState(ButtonState(previousNextState.text, false))
backButton.changeState(
ButtonState(UIBundle.message("ui.button.back"), true) {
backButton.changeState(previousBackState)
nextButton.changeState(previousNextState)
mainWindow.loadCurrentTemplate()
}
)
}
}

Expand All @@ -172,14 +179,7 @@ class MainPluginPanelFactory : ToolWindowFactory {
fun checkInputs(): Promise<Boolean> =
mainWindow.executeJavaScriptAsync("allChecked()").then { it.toBoolean() }

fun setNextAction(listener: ActionListener) = nextButton.addListener(listener)
fun setNextAction(listener: ActionListener) = nextButton.setListener(listener)

fun setBackAction(listener: ActionListener) = backButton.addListener(listener)

private fun JButton.addListener(listener: ActionListener) {
actionListeners.forEach {
removeActionListener(it)
}
addActionListener(listener)
}
fun setBackAction(listener: ActionListener) = backButton.setListener(listener)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jetbrains.research.tasktracker.ui.main.panel

import com.intellij.ide.browsers.BrowserLauncher
import com.intellij.ide.ui.LafManagerListener
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Disposer
Expand All @@ -9,6 +10,7 @@ import org.cef.browser.CefFrame
import org.cef.handler.CefLoadHandlerAdapter
import org.intellij.lang.annotations.Language
import org.jetbrains.concurrency.Promise
import org.jetbrains.research.tasktracker.ui.main.panel.models.LinkType
import org.jetbrains.research.tasktracker.ui.main.panel.models.Theme
import org.jetbrains.research.tasktracker.ui.main.panel.template.DefaultErrorPage
import org.jetbrains.research.tasktracker.ui.main.panel.template.HtmlTemplate
Expand Down Expand Up @@ -40,6 +42,7 @@ class MainPluginWindow(service: MainWindowService) {
}
}
)
listenRedirectToDefaultBrowser()
Disposer.register(service, windowBrowser)
}

Expand Down Expand Up @@ -86,6 +89,19 @@ class MainPluginWindow(service: MainWindowService) {
fun loadHtmlTemplate(template: HtmlTemplate) =
windowBrowser.loadHTML(template.htmlContent).also { currentTemplate = template }

fun loadCurrentTemplate() {
loadHtmlTemplate(currentTemplate)
}

/**
* Redirecting to external websites in default browser.
*/
private fun listenRedirectToDefaultBrowser() {
jslinkProcess(LinkType.DEFAULT_BROWSER) {
BrowserLauncher.instance.open(it)
}
}

companion object {
const val JS_QUERY_POOL_SIZE = 100
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package org.jetbrains.research.tasktracker.ui.main.panel

import org.jetbrains.research.tasktracker.ui.main.panel.models.ButtonState
import org.jetbrains.research.tasktracker.ui.main.panel.models.LinkType
import org.jetbrains.research.tasktracker.util.UIBundle
import java.awt.event.ActionListener
import javax.swing.JButton

fun createJButton(
Expand All @@ -11,3 +14,54 @@ fun createJButton(
isBorderPainted = isBorderPaintedProp
isVisible = isVisibleProp
}

fun MainPluginWindow.jslinkProcess(type: LinkType, action: (param: String) -> Unit) {
with(type) {
val preventCode = if (prevent) {
"""
link.addEventListener('click', function(event) {
event.preventDefault();
});
""".trimIndent()
} else {
System.lineSeparator()
}
executeJavascript(
"""
const elements$name = document.querySelectorAll('$queryFilter');
for (const link of elements$name) {
$preventCode
link.onclick = get_link$name
}

function get_link$name() {
link = this.getAttribute('$getAttribute');
""",
"}",
"link"
) {
action(it)
null
}
}
}

/**
* Creates new JButton state and return previous JButton state.
*/
fun JButton.changeState(buttonState: ButtonState) {
buttonState.actionListener?.let {
setListener(buttonState.actionListener)
}
this.text = buttonState.text
isVisible = buttonState.isVisibleProp
}

fun JButton.getState(): ButtonState = ButtonState(text, isVisible, actionListeners.firstOrNull())

fun JButton.setListener(listener: ActionListener) {
actionListeners.forEach {
removeActionListener(it)
}
addActionListener(listener)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.jetbrains.research.tasktracker.ui.main.panel.models

import java.awt.event.ActionListener

data class ButtonState(
val text: String,
val isVisibleProp: Boolean,
val actionListener: ActionListener? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.jetbrains.research.tasktracker.ui.main.panel.models

/**
* Types of redirecting links.
*/
enum class LinkType(val queryFilter: String, val prevent: Boolean, val getAttribute: String) {
DEFAULT_BROWSER(".defaultBrowser", true, "href"),
JCEF("a:not(.defaultBrowser):not(.file)", false, "href"),
FILE(".file", true, "data-value")
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,24 @@ class AgreementTemplate(private val agreements: List<Agreement>) : HtmlBaseFileT
buildString {
append("""<div><input id="$index" type="checkbox" name="$index" """)
append("""${if (element.required) "required" else ""}>""")
append("""<label for="$index">${element.text.withBr()}</label></div>""")
append("""<label for="$index">${element.toHtml()}</label></div>""")
}
}.joinToString("<br>")

private fun String.withBr() = replace(System.lineSeparator(), "<br>")
private fun Agreement.toHtml(): String {
var html = text.replace(System.lineSeparator(), "<br>")
if (openLinkInDefaultBrowser) {
html = html.replace(HREF_PATTERN) { matchResult ->
val href = matchResult.groupValues[1]
"""<a class="defaultBrowser" href="$href">"""
}
}
return html
}

companion object {
val HREF_PATTERN = """<a href="([^"]*)">""".toRegex()

fun loadCurrentTemplate(): AgreementTemplate {
val config = TaskTrackerPlugin.mainConfig.agreementConfig
?: error("agreementConfig has not initialized yet!")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ agreements:
example
required: false
- text: "Example <a href=\"https://github.com/JetBrains-Research/tasktracker-3\">link</a>"
- text: "Example link in JCEF <a href=\"https://github.com/JetBrains-Research/tasktracker-3\">link</a>"
openLinkInDefaultBrowser: false
- text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,"
Loading