HipChat and the Adobe Creative SDK: A perfect pairing

Reading Time: 5 minutes

I’ve built many add-ons on top of Atlassian products over the last five years. In that time, the most satisfying add-ons I’ve built were also the simplest. Since HipChat Connect launched in beta last November, I’ve been experimenting with new ways to bring tighter integrations with apps like Uber, Facebook and Twitter, into HipChat. Today, I’m sharing how I built my most powerful, yet simplest add-on using the Adobe Creative SDK.

Here’s the idea…

One of HipChat Connect’s most interesting capabilities is the ability to action on a message. If you’ve used HipChat before, you’re probably familiar with the fact that you can upload and share images (or links to images) with your colleagues. This is a useful feature if you’re part of a design or product team and often share mockups. It’s also generally useful when you just want to share a photo or meme you found on the web. Let’s be honest, we all share a lot of memes in HipChat.

The idea I’ve long wanted to implement in HipChat is the ability to annotate these images then re-share them with the team. This is useful when you want to convey an idea with your designer or just want to point out a bug with your product team. So, I searched the web for an open source library that allowed you to annotate images… and there are lots of them (including one we use within JIRA Capture). However, what I ran into instead was Adobe’s Creative SDK

The Adobe Creative SDK exposes a set of APIs to give their users access to creative tools and Adobe’s Creative Cloud platform directly from their own app. It’s the engine behind some of the best creative apps on the market and at the heart of Adobe’s own mobile offerings. I decided to use Adobe’s Image Editing UI component to build an image editor within HipChat. This Image Editor is not your dad’s paint.exe – it’s a modern image editor that runs entirely in a web browser (or mobile app). While having an Instagram like add-on might not be the most useful thing for your teams, I thought I’d take a crack at implementing it within HipChat anyway.

It really is quite amazing what you can build when you have an amazing SDK or API in hand. I’ve spent most of my professional life building products on top of other people’s APIs and SDKs (as many of you have). However, building compelling products usually aren’t that trivial. Only once in a while are we reminded that simplicity in design and architecture and clear intents are what lead to purposeful and useful products. In this case, the combination of HipChat’s message action API and Adobe’s Creative SDK was a perfect pairing.

How does it work?

Let’s start with the HipChat message action capability:


"action": [
    {
        "key": "edit",
        "name": {
            "value": "Edit this image"
        },
        "target": "editor",
        "location": "hipchat.message.action",
        "conditions": [
            {
                "type": "or",
                "conditions": [
                    {
                        "condition": "message_matches",
                        "params": {
                            "type": "image"
                        }
                    },
                    {
                        "condition": "message_matches",
                        "params": {
                            "type": "file",
                            "file_type": "image"
                        }
                    },
                    {
                        "condition": "card_matches",
                        "params": {
                            "style": "image"
                        }
                    }
                ]
            }
        ]
    }
]

The snippet above is the message action capability declared in the HipChat Connect descriptor. This describes the action and where that action should be enabled. In this case, we use conditions to make sure that the “Edit this image” action only shows up on messages with actual images in them.

That’s really it on the add-on capabilities side of things. The rest of the code needed is inside the add-on dialog itself. Adobe’s Creative SDK for the web is pretty simple to implement Most of it can really be done within a few dozen lines of client-side code. Here’s the JavaScript code that runs in the add-on dialog itself:


(function(ImageEditor, global) {
    // Add support for HipChat's light and dark mode
    var theme = getParameterByName('theme').indexOf('light') > -1 ? 'minimum' : 'dark';
    document.body.className = theme;
    // Registers listeners that can launch the editor. These are executed
    // when the dialog is opened. Image URL is passed in through the
    // message object
    HC.register({
        "edit": function(message) {
            if (message.media) {
                launchEditor(message.media.url, message.media.name);
            }
            if (message.card) {
                launchEditor(message.card.url);
            }
        }
    });
    // Main fn to launch the editor
    function launchEditor(imgUrl, imgName) {
        var imageEditor = new ImageEditor({
            apiKey: config.settings.apiKey, // Obtain an API key from Adobe
            theme: theme,
            tools: 'all',
            noCloseButton: true,
            launchDelay: 0,
            appendTo: 'image-editor', // DOM element to append the editor to
            onLoad: function() {
                // Loads image into the DOM
                var img = new Image();
                img.onload = function(id, src) {
                    imageEditor.launch({
                        image: img.id,
                        url: img.src
                    });
                };
                img.id = "img";
                img.src = imgUrl;
                img.className = 'invisible';
                document.body.appendChild(img);
            },
            onSaveButtonClicked: function() {
                imageEditor.getImageData(function(img) {
                    // Use HipChat's JS API to add the edited image (base64
                    // encoded) to the chat input component
                    HipChat.chat.addFileForUploadWithBase64(img, imgName);
                    HipChat.dialog.close();
                })
                return false;
            }
        });
    }
})(Aviary.Feather, window);

Adobe requires you to register your app and use the token they create for you. This token is used when you initialize the editor but isn’t used for anything else other than tracking the usage of the app.

The rest of the code needed is the code that bridges the action, launching and dismissing the editor, and passing the edited message back to HipChat’s chat input component.

Now for some magic

Here’s the magic… this add-on is a static add-on. It doesn’t require an add-on server and can be hosted on any static web host. So, the best part of this was the fact that I didn’t have to set up hosting, worry about a database, and figure out how to keep this service working. Instead, I decided to push my code to Bitbucket then use a Bitbucket add-on called Aerobatic. Aerobatic is a simple static web host that deploys your code to Amazon’s Cloudfront (CDN) and it does this every time you push your code to Bitbucket. It even supports automated builds using NPM so you can use webpack and the like to package your scripts. This makes deploying your add-on simple a git push to Bitbucket.

If you need to host any static sites, I highly recommend Aerobatic. It’s a great service coupled with Bitbucket. It even allows you to proxy API calls so you can make Ajax calls without cross-domain restrictions.

Where are we going with this?

I’ve only touched the surface with Adobe’s Creative SDK. Next, I’d like to implement Adobe’s Creative Cloud Asset Browser. This will allow you to access all your assets from the Creative Cloud so you can easily share them with your team. Stay tuned for this. In the meantime, feel free to try out the Image Editor.

I’m always on the lookout for the easiest and most useful add-ons to build. I’m not sure I’ll find one to top this any time soon, but I encourage you all to do it. Here’s a challenge, maybe one of you can build this same add-on on top of Bitbucket, JIRA, and Confluence. Any takers?