I’m trying to implement a feature through ScriptRunner that involves extending the Jira “issue details” screen using a web fragment (a button), which in turn shows a dialog box with a form. For the purpose of demonstrating this issue, I have kept the implementation to a minimum (the form only contains a couple of Radio Buttons and a Submit button).
To summarize:
However, when I execute the following sequence, my JavaScript somehow thinks bumps up the radio button count by 2 upon every single invocation of this sequence.
Interestingly, if you refresh the web page after exiting the dialog, the dialog shows the correct number again, and both radio buttons are selectable.
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
@BaseScript CustomEndpointDelegate delegate
showForm_Debug { MultivaluedMap queryParams ->
def header =
"""
<!-- Dialog header -->
<header class="aui-dialog2-header">
<h2 class="aui-dialog2-header-main">Test Form</h2>
<a class="aui-dialog2-header-close">
<span class="aui-icon aui-icon-small aui-iconfont-close-dialog">Close</span>
</a>
</header>
"""
def formContent =
"""
<form class="aui" name="crb_main_form">
<div class="field-group" id="cal_fieldgroup_id1">
<label for="cal_fieldgroup_id1">Phase Found</label>
<div class="radio">
<input class="radio" type="radio" checked="checked" name="radiobuttons_phase_found" id="rbStaging">
<label for="rbStaging">Pre-Production</label>
</div>
<div class="radio">
<input class="radio" type="radio" name="radiobuttons_phase_found" id="rbProduction">
<label for="rbProduction">Production</label>
</div>
</div>
</form>
"""
def footer =
"""
<!-- Dialog footer -->
<footer class="aui-dialog2-footer">
<div class="aui-dialog2-footer-actions">
<form id="my-custom-sr-dialog-form" class="aui" action="javascript:getSelectedPhase()">
<button id="submit-button" class="aui-button aui-button-primary">Submit</button>
</form>
</div>
</footer>
"""
def scripts =
"""
<script>
function getSelectedPhase()
{
var radios = document.getElementsByName('radiobuttons_phase_found');
var msg = "Number of radio buttons in the group: " + radios.length
alert(msg);
}
</script>
"""
def dialog =
"""
<section id="static-dialog" class="aui-dialog2 aui-dialog2-large" role="dialog">
${header}
${formContent}
${footer}
${scripts}
</section>
"""
Response.ok().type(MediaType.TEXT_HTML).entity(dialog.toString()).build()
}
I'm at a loss to understand this behavior, and I'm hoping someone from this community could shed some light and hopefully point to what I'm doing wrong here and/or offer suggestions on how to fix this.
Many thanks,
Kamran
Hi Kamran
I've encountered this.
It turns out that every time you click the button, your dialog html is embedded into the DOM and when you close it, the html is still in there.
Every time you click the button, you get another copy in the DOM.
You can avoid this by adding the data-aui-remove-on-hide attribute to the section tag
<section id="static-dialog" class="aui-dialog2 aui-dialog2-large" role="dialog" data-aui-remove-on-hide="true">
I would encourage you to explore using the MarkupBuilder to create your dialog and saving your javascript in a separate file (which you can maintain in an IDE that is good for javascript)
Here is how I would implement your form:
def writer = new StringWriter()
def dialog = new MarkupBuilder(writer)
dialog.section(role: 'dialog', id: 'static-dialog', class: 'aui-layer aui-dialog2 aui-dialog2-large', 'aria-hidden': true, 'data-aui-remove-on-hide': true) {
header(class: 'aui-dialog2-header') {
h2(class: 'aui-dialog2-header-main') { dialog.mkp.yield("QAD Log Work Settings") }
}
div(class: 'aui-dialog2-content') {
form(class: 'aui', name:'crb_main_form'){
fieldset(class: 'group',id:'cal_fieldgroup_id1'){
legend { span { dialog.mkp.yield('Phase Found') } }
div(class: 'radio') {
input(class: 'radio', type: 'radio', id: 'rbStaging', name: 'radiobuttons_phase_found', value: 'rbStaging')
label(for: 'rbStaging') { dialog.mkp.yield "Pre-Production" }
}
div(class: 'radio') {
input(class: 'radio', type: 'radio', id: 'rbProduction', name: 'radiobuttons_phase_found', value: 'rbProduction',)
label(for: 'rbProduction') { dialog.mkp.yield "Production" }
}
}
}
}
foooter(class: 'aui-dialog2-footer') {
div(class: 'aui-dialog2-footer-actions') {
button(id: 'cancel-button', class: 'aui-button aui-button-link cancel', onclick: 'closeDialog()') { dialog.mkp.yield "Cancel" }
button(id: 'submit-button', class: 'aui-button aui-button-primary', type: 'submit', accesskey: 's', value: 'Submit', onclick: 'getSelectedPhase()') { dialog.mkp.yield "Submit" }
}
}
script(type: 'text/javascript') {
def scriptFile = new File("$jiraHome/scripts/path/to/your/javascript/file.js")
dialog.mkp.yieldUnescaped(scriptFile.getText('UTF-8'))
}
}
Response.ok().type(MediaType.TEXT_HTML).entity(writer.toString()).build()
If you haven't already found this... I find it invaluable: https://aui.atlassian.com/aui/7.9/docs/dialog2.html
Thank you so much, you're awesome! :) This took care of both problems I described in my post. I also appreciate the explanation of what's going on with the DOM every time the button is clicked - it makes a lot of sense now.
I'm still very new to ScriptRunner and Groovy, and I sincerely appreciate your suggestions about using MarkupBuilder and an IDE for development. Wondering if you'd have a recommendation for any good IDE out there (I use Windows).
Thanks again!
Kamran
PS: I've always wondered what name you went by if I had to address you by name (Peter or Peter-Dave?) :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Glad I could help.
I use Intelij community edition as my IDE. There are some instructions on the adaptavist site on how to configure.
When you start with their sample project (even if you have no plans to create a plugin or anything like that) the IDE will download all the relevant dependencies so that you get the full autocomplete experience.
I don't use a local instance of Jira or use any debug configuration. I just have WINSCP set up to copy my local files to my DEV server. This way every time I change a line of code, it is immediately picked up by my DEV server and I can test the results there.
I encourage people to call me by both: "Peter-Dave". But I'll answer to either.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.