Wednesday, June 8, 2011

Using Javascript to Manipulate DOM Elements in Hype

I’ve been having a lot of fun playing with Tumult’s recently-released tool called Hype for the Mac. It’s a time-line based tool for creating rich animated HTML5 content that runs natively in most modern browsers. We’ve been hearing for quite some time that Flash is no longer needed with all of HTML5 and CSS3’s capabilities, but no one had come up with a design-centric tool for creating that content. That’s where Hype has stepped in. For anyone familiar with working in Adobe’s Flash design tools, Hype should be fairly straightforward to work with. I had an interactive mobile site targeted at the iPhone finished in a few hours, with stuff animating into view, and custom buttons triggering animations between scenes. The problem I ran into though came when I wanted to start thinking about getting dynamic content from the outside world into the site instead of coding everything inside the Hype-generated container (most of the stuff lives in an ugly javascript file so don’t plan on working with content you’ve put into Hype after you’ve ‘compiled’ it down). That’s the one place I think it falls a little short. Although it’s nice that, unlike Flash, it exports to pure javascript/css, it’s still kind of an enclosed blob for all intents and purposes once you’ve moved out of the Hype application.

So, here’s the design I was trying to achieve. I had a home page that I wanted to populate with some dynamic content from my FriendFeed account via RSS. I decided to use Google’s javascript API for the RSS communication, and that’s pretty straightforward and well-documented on Google’s site. The problem I ran into was getting that code integrated with Hype. This is how I got it working.

Basically Hype has some event-hooks where you can trigger a javascript function. For what I was trying to achieve it made the most sense to tap into the hook that occurs after the animation for the home page has completed. I added a function called loadRSSContent and did the event-wiring in the GUI, which is trivially simple. Then I added a couple of lines of javascript to that function that would call another function that lives on the .html page that houses the Hype container. It’s not very well documented on the Hype site, but you can use any javascript functions/libraries within Hype that will eventually be available on the enclosing page at runtime. There is currently no support for importing these assets at design-time though (although that seems like an easy feature to add) so you’re flying-blind until you run the export and embed the container on a page. This is why I would suggest getting everything running on a test page and then only moving the pieces into Hype that are necessary to manipulate the DOM elements on the timeline. You’ll understand what I mean when you see the code.

So, on my home scene I added a Hype text box, and within it I created a div with id=“rssDiv”.

On the ‘On Animation Complete” event for the scene, the javascript in Hype looks like this:

function loadRSSContent(hypeDocument, element)
  //get the content for the rssDiv from a function outside of Hype
  var rssDiv = document.getElementById("rssDiv");
  rssDiv.innerHTML = getRSSContent();
}

The javascript that does the work lives on the .html page (outside of the Hype container). I should also point out what I’m doing here. I’m using the initialize() function to put the RSS html into a hidden element on the page, and then the getRSSContent() function takes that content and hands it back inside the Hype container when it requests it. The reason I’m doing it this way is because the DOM gets built dynamically with Hype, so you don’t want to try to manipulate it directly from outside of the Hype container. Also, the initialize() function can run as soon as the Google API is loaded and get the content ready while Hype is doing its animation stuff.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv=“Content-Type” content=“text/html; charset=utf-8”>
<meta http-equiv=“X-UA-Compatible” content=“chrome=1”>
<meta name=“viewport” content=“user-scalable=yes, width=320px” />
<script type=“text/javascript” src=“https://www.google.com/jsapi?key=yourkey”></script>
<script src=“https://www.google.com/uds/?file=feeds&v=1” type=“text/javascript”></script>
<script type=“text/javascript”>

function initialize() {
  var feed = new google.feeds.Feed(“http://friendfeed.com/kevnls?format=atom&num=4”);
  feed.setNumEntries(4);
  feed.load(function(result) {
    if (!result.error) {
      var html = ‘’;
      for (var i = 0; i < result.feed.entries.length; i++) {
        var entry = result.feed.entries[i];
        html += ‘<a href=“’ + entry.link + ‘” target=“_blank”>’ + entry.title + ‘</a><br/><br/>’;
      }
      document.getElementById(“hiddenElement”).value = html;
    }
  });
}

google.setOnLoadCallback(initialize);

function getRSSContent() {
  var hiddenElement = document.getElementById(“hiddenElement”);
  var rssResult = hiddenElement.value;
  return rssResult;
}
  
</script>
<title>kevnls</title>
        <style>
                body {
                        background-color: #FFFFFF;
                        margin: 0px;
                }
        </style>
</head>
<body>
        <input type=“hidden” id=“hiddenElement” value=“” />
        <div style =“margin:auto;width:320px”>  
        <!-- copy these lines to your document: -->
        <div id=“kevnls_hype_container” style=“position:relative;overflow:hidden;width:320px;height:396px;”>
                <script type=“text/javascript” src=“mobile_Resources/kevnls_hype_generated_script.js?43552”></script>
        </div>
        <!-- end copy -->
        </div>
</body>
</html>

The result of all of this can be seen here: http://kevnls.com/mobile

Hopefully this design will prove useful to someone (besides me).

Until next time.

No comments: