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.

Tuesday, April 19, 2011

Using jQuery to Disable a Link on a Specific Day of the Week

My company has a regular scheduled downtime of our messaging-bus each Sunday.  This brings down some functionality on our site, so I needed to disable the links for those resources automatically, but instead of hiding them or pointing them somewhere else, I decided it would be nice to give the user some information about what's going on right there on the page when they click on one of the disabled links.  I came up with the following piece of code which will do that for any link with class="TibcoRequired":

<!--script to disable links to Tibco-reliant tests on Sundays-->
     
<link href="/Resources/Scripts/jQuery/css/redmond/jquery-ui-1.8.1.custom.css" rel="stylesheet" type="text/css"/>
<script src="/Resources/Scripts/jQuery/js/jquery-1.4.2.min.js"></script>
<script src="/Resources/Scripts/jQuery/js/jquery-ui-1.8.1.custom.min.js"></script>

<div id="dialog" title="Dialog Title" style="display:none;"><p>This test cannot be taken on Sundays due to a regular
  scheduled downtime of the result-tracking system.</p></div>

<script type="text/javascript">
      $('.TibcoRequired').click(function () {
        var d = new Date();
        var today = d.getDay();
        if (today == 0) {
          $('#dialog').dialog({ title: 'Message' });
          return false;
        }
      });
</script>

<!--script-->

Thursday, January 13, 2011

Creating a custom Model and passing a Linq to SQL query to a View in .net MVC

Another one of my 'I was trying to do this and having no luck finding solutions' posts, so I'll post my solution and hopefully it will help someone else in the same predicament.

This time I was working on a .NET MVC project, and trying to do some reporting.  Basically it's a simple app that records users' steps-per-day.  The users are assigned to teams and I wanted to create a page that showed the ranking of the different teams each month based on their total number of steps.  As you can imagine, I had three tables.  tblTeams, tblUsers, and tblSteps.  So, my problem was, I have a model built using Linq to SQL, and it works fine if you're working with one of the objects that relates to its table.  But, in this case I just wanted to do a simple join query, with some grouping, and return that to the view to create an html table of the different teams and their totals.  So, here's how I made it work:

First off, I created a new very simple model containing the class to hold the results of the query:

namespace StepsChallenge.Models
{
    public class TeamTotalsModel
    {
        public string TeamName { get; set; }
        public string Sum { get; set; }
    }
}

Then, in my view I added a reference to this model:

Inherits="System.Web.Mvc.ViewPage<IEnumerable<StepsChallenge.Models.TeamTotalsModel>>"

OK, now we're wired-up.  On to the data.

I wrote a Linq to SQL query that looked like this in my controller and passed it into an instance of the model class:

public class HomeController : Controller
{
        public ActionResult Index()
        {
            //get monthly steps for the teams
            var allTeamsMonthlySteps = from stepRecord in homeModel.Steps
                                       join userRecord in homeModel.Users
                                       on stepRecord.EmpID equals userRecord.EmpID
                                       join teamRecord in homeModel.Teams
                                       on userRecord.TeamID equals teamRecord.TeamID
                                       where stepRecord.Date.Month == DateTime.Now.Month
                                       group stepRecord by teamRecord.TeamName into result
                                       orderby result.Key ascending
                                       select new TeamTotalsModel
                                       {  
                                          TeamName = result.Key.ToString(),
                                          Sum = result.Sum(r => r.Steps).ToString()
                                       };

            return View(allTeamsMonthlySteps);
         }
}

Then finally, back at the view I wrote something like this:

    <table>
        <tr>
            <th>
                TeamName
            </th>
            <th>
                Sum
            </th>
        </tr>

    <% foreach (var item in Model) { %>
  
        <tr>
            <td>
                <%= Html.Encode(item.TeamName) %>
            </td>
            <td>
                <%= Html.Encode(item.Sum) %>
            </td>
        </tr>
  
    <% } %>

    </table>

So, this isn't all that complicated, but the problem I was having is that every search I did on almost every piece of this pointed me back to all the Visual Studio drag-and-drop BS for working with Linq to SQL models where there's a one-to-one relationship between objects and tables.  And, I couldn't find much help at all on writing a Linq to SQL query with multiple joins, grouping, and 'where' clauses, all together, and passing it to the view.

Anyway, maybe some poor slob like me will stumble across this and find what he needs.  Until next time.

Friday, December 3, 2010

Apache configuration for SimpleSAMLphp on OS X Snow Leopard

I needed to do some testing with the SimpleSAMLphp (http://simplesamlphp.org/) application today. I’m not a php developer so my mac wasn’t setup to run php in Apache. That part was trivially simple to setup, but I ran into problems trying to get the SimpleSAMLphp application running in a configuration that made sense to me. What I wanted to do was install the application into my /Sites/ directory, and create another directory under /Sites/ that would act as the php site that uses it. It may seem odd to install the app in the sites directory, but I just wanted to keep the two together. So, the directory structure looked like this:

~/Sites/simplesamlphp/
~/Sites/phpsite/

Then, I wanted to change my Apache configuration so that http://localhost/ would remain the same (pointing at /Library/WebServer/Documents/), http://phpsite/ would point to ~/Sites/phpsite/, and http://phpsite/simplesaml would point to ~/Sites/simplesamlphp/www.

It took some trial and error, but I ended up with these configurations:

First I uncommented the following line in the /etc/apache2/httpd.conf file:

Include /private/etc/apache2/extra/httpd-vhosts.conf

Then I went to that file and changed the following line from this:

NameVirtualHost *:80

to this:

NameVirtualHost 127.0.0.1:80

and, added this:

<VirtualHost phpsite>
DocumentRoot "/Users/sysadmin/Sites/phpsite"
ServerName phpsite
<Directory "/Users/sysadmin/Sites/phpsite">
Options FollowSymLinks MultiViews Includes
AllowOverride All
Order allow,deny
Allow from all
</Directory>
Alias /simplesaml /Users/sysadmin/Sites/simplesamlphp/www
</VirtualHost>

Then I went to my /etc/hosts file and added this line:

127.0.0.1      phpsite

Then, a quick Apache restart and everything was running smoothly.

http://localhost - still points to /Library/WebServer/Documents
http://localhost/~sysadmin/ - still points to ~/Sites/
http://phpsite - points to ~/Sites/phpsite
http://phpsite/simplesaml - points to ~/Sites/simplesamlphp/www

Obviously you wouldn’t want to configure it this way if this was a production server, but when I’m doing development work like this I’d prefer to keep everything under my own home folder.

Thursday, February 18, 2010

DRY up your content using ASP.NET user controls


I was doing a little code-cleanup on an app I support this week.  I was trying to find some places where I could implement the DRY (don't repeat yourself) methodology.  It was fairly easy picking, because this app is leaning a little more toward the RYE (repeat yourself everywhere) methodology.  Anyway, I came up with a way to use ASP.NET User Controls in a project to move some of that repetitive content out of the individual pages, and into a centralized place.

This may not be anything new to anyone, but I had never thought of using a user control for content.  I created two controls, one for some contact information that was used on every page (pointing to different departments in the company), and one to encapsulate some page framework that needed to be slightly different depending on where the application was deployed (I was able to put this logic into the user control and read the location from the web.config).

The contact control renders asp labels to display content on the page, and the framework control renders standard divs.  The code had to be slightly different in the code-behind to search for the controls, but once you set up the controls this way, you wouldn't need to ever change the c# code if you wanted to add a new label or div to the .ascx file.

Anyway, like I said I just came up with this idea earlier this week, but I'm anxious to add it to the toolkit.  I'm already thinking of some more uses for this.  You could perhaps have a 'snippets.ascx' file that had all the reusable content, and enclose each piece in a div.  Then all you'd have to do is call the user control in your app with the name of the div you wanted to render.

i.e. <userControl:Snippets ID="SnippetControl" DivID="WhateverDivIwantToShow" runat="server" />

I'll add the relevant code.  Should be easy to see what I'm talking about.

------------------------------------------------------------------


front-end for user control to deterministically expose asp label controls:

<asp:Label ID="Payroll" Visible="false" runat="server">
<p>
    For questions regarding the content of your documents contact the Payroll Department at 555-5555.
</p>
</asp:Label>

<asp:Label ID="HelpDesk" Visible="false" runat="server">
<p>
    For technical questions or support please contact the Help Desk at 555-5555.
</p>
</asp:Label>


   
c# code-behind for user control:

public partial class Contact : System.Web.UI.UserControl
{
    string strLabelID = string.Empty;

    public string LabelID
    {
        get
        {
            return strLabelID;
        }
        set
        {
            strLabelID = value;
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        foreach (Control ctrl in Controls)
        {
            if (ctrl is Label)
            {
                if (ctrl.ID == strLabelID)
                {
                    ctrl.Visible = true;
                }
            }
        }
    }
}



usage of control:

<ucContact:Contact ID="PayrollContact" LabelID="Payroll" runat="server" />

<ucContact:Contact ID="HelpDeskContact" LabelID="HelpDesk" runat="server" />

------------------------------------------------------------------------------

Another Example:

front-end for user control to deterministically expose generic div elements:

<div id="Header" visible="false" runat="server">
    put stuff in here for the header
</div>

<div id="Footer" visible="false" runat="server">
    put stuff in here for the footer
</div>



c# code-behind for user control:

public partial class PortalFramework : System.Web.UI.UserControl
{
    private string strDivID = string.Empty;

    public string DivID
    {
        get
        {
            return strDivID;
        }
        set
        {
            strDivID = value;
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        foreach (Control ctrl in Controls)
        {
            if (ctrl is HtmlGenericControl)
            {
                if (ctrl.ID == strDivID)
                {
                    ctrl.Visible = true;
                }
            }
        }
    }
}



usage of control:

<ucFramework:PortalFramework ID="PortalFrameworkHeader" runat="server" DivID="Header" />

<ucFramework:PortalFramework ID="PortalFrameworkFooter" runat="server" DivID="Footer" />

Friday, December 18, 2009

Forray into xsl

This summary is not available. Please click here to view the post.

Tuesday, September 22, 2009

TestDisk to the rescue!

Last night I had a serious problem with my netbook. I'm running Ubuntu on a Dell mini with most of the data on an SD card. Anyway, I think the SD card got messed up when the machine went into hibernation, and when I opened the lid I was getting cryptic messages about the drive not being able to mount. I tried the usual tools, fsck, dumpe2fs, gpart, etc. Nothing doing. Everything that was working for other people wasn't working for me... Kept researching the messages I was getting from the various tools:

Block bitmap for group 1 not in group

Bad Magic Number in Superblock

Disk doesn't contain a valid partition table

etc. etc.

The last one ended up being the clue. Found a utility called TestDisk and it had me fixed up in less than 15 minutes.

http://www.cgsecurity.org/wiki/TestDisk_Step_By_Step

It was able to figure out the partitions based on the good data still on the disk. Then it was just a matter of using the tool to rewrite the partition table and I was back in business!