In this article you’ll learn how to create a setup-less plugin that injects itself into Jira issue page. Also you’ll see how to do a Drag and Drop with modern browsers in a couple of lines 🙂
Also in this course you’ll also become familiar with writing Jira plugins. So let’s move on.

Let me in, please!

So, I’m scratching my head wondering how can I attach myself to the issue page. Let’s use a custom field! Simple, elegant and easy to code solution. Isn’t it?
Sure it is but it has one drawback – admin has to configure it. Is there a better way?
Atlassian Plugins Framework 2.5 comes to the rescue with web-resource/context which allows you to automatically attach resources to predefined contexts (like user or admin pages). Oh no, it doesn’t! I want it to work with Jira 4.1 and APF 2.5 is not there 🙁
So, am I out of luck? No! I just need a couple lines more. Here comes my servlet-filter 🙂

<servlet-filter name="Jira Drag and Drop Attachment Resources"
key="servlet-filter" class="com.atlassian.jira.plugins.dnd.attachment.AttachDndResourcesFilter"
location="before-dispatch" weight="200">

So what does it do? It will process all requests matching /browse/* (issue screens mostly) and it will attach my resource with those lines:

public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain)
throws IOException, ServletException
WebResourceManager webResourceManager = ComponentManager.getInstance().getWebResourceManager();
filterChain.doFilter(servletRequest, servletResponse);

Now, every time someone opens the issue page my code will be included.

I’m in, let’s hack 🙂

Chop, chop, chop.
That was easy – just create HTML using jQuery and attach it at the end of right column. Remember about proper mark-up and CSS and it will look like the rest of elements. This will be the drop zone.
Yes sir, I can interact with drag and drop events.

.bind("dragenter", dndAttachment.ignoreEvent)
.bind("dragover", dndAttachment.ignoreEvent)
.bind("drop", dndAttachment.handleDrop);

Function ignoreEvent ignores and prevents propagation, so the browser doesn’t try to open files. Upload is done in handleDrop after the file was dropped onto the zone.

I have it, now let’s send it

Hmm, how to send it? Will I have to create a multipart form request body, write a lot of code and worry about handling binary data? Not any more:

var xhr = new XMLHttpRequest(), upload = xhr.upload;
upload.onprogress = function(event) {
// handle on progress using new API
};"POST", contextPath + "/rest/jira-dnd-attachment/1.0/issue/" + key + "/attachments?filename=" + file.fileName, true);
xhr.onreadystatechange = function(event) {
if ( == 4) {
// handle end of upload

All you need to do is to actually send elements from event.originalEvent.dataTransfer.files which is available as an argument to handleDrop.
Everything closes in 200 lines of pretty formatted JavaScript.

Catch me if you can

Receiving a file is straight-forward as you can see.
Get a file, copy to temp, handle to AttachmentManager, create IssueUpdateBean to save trace in the issue history. Don’t forget to do security check by the way and you should be fine.

That’s all folks! Thanks for coming.


Under the hood of Jira Drag and Drop Attachments plugin