.Net Code Monkey RSS 2.0
 Sunday, February 22, 2009

Background

I was recently asked by a friend to help him implement the website code part of Brandon Fuller's 'Now Playing' plugin for iTunes. The code Brandon provides is PHP, and I felt that would be limiting if my friends website ever had to move to a non PHP enabled web server. With this in mind I decided to convert and modify his PHP script to be JavaScript only. This article covers the code created to do so.

The Solution

Below is the javascript file to include on your website.

Javascript Code

You will need to set up a few values in the pseudo-constants section of the code first.

  • REMOTE_XML_URL - is the remote url for the 'now_playing.xml' published by Barndon's ITunes plugin.
  • DISPLAY_ARTIST, DISPLAY_TITLE and DISPLAY_ALBUM  - are flags for if to display these element.

The remainder of the constants all declare element IDs or css classes for the elements the javascript creates.

Lastly you will also need to set the _artworkUrl variable to point to the the default artwork url for when album artwork is not available.

 

/*
File:       NowPlaying.js
Author:     Duane Wingett
Date:       21st February 2009
Purpose:    For use with Brandon Fuller's "Now Playing" iTunes addon, see:
            http://brandon.fuller.name/archives/hacks/nowplaying/
            for more details.
Browser Compatability:
            checked (Tested on)
            IE 6.0.2
            Opera 9.52
            Firefox 3.0.5
            Netscape 9.0b3
            Safari (Windows) 3.2.1
            Chrome 1.0
Usage Policy:
            You are free to use / distribute this code without charge, 
            providing this acknowledgement remains intact ane no
            profit is gained from use.            
*/

// Constant Declarations
var REMOTE_XML_URL = 'http://www.mySite.com/NowPlaying/now_playing.xml'; // Remote location of NowPlaying xml file
var DISPLAY_ARTIST = true;
var DISPLAY_TITLE = true;
var DISPLAY_ALBUM = true;
var OUTER_CONTAINER_IDENTITY = 'NowListeningTo';
var IMAGE_CONTAINER_IDENTITY = 'ListeningImageContainer';
var TEXT_CONTAINER_IDENTITY = 'ListeningTextContainer';
var OUTER_CONTAINER_CSS_CLASS = '';
var IMAGE_CONTAINER_CSS_CLASS = 'FloatLeft';
var TEXT_CONTAINER_CSS_CLASS = 'FloatLeft StudioInfoTextContainer RightBorder';
var ARTIST_TEXT_CSS_CLASS = 'StudioInfoText';
var TITLE_TEXT_CSS_CLASS = 'StudioInfoText';
var ALBUM_TEXT_CSS_CLASS = 'StudioInfoText';
var IMAGE_CSS_CLASS = 'NowPlaying';
var CONTENT_DIV_ID = 'x'; // ID of div to insert NowPlaying html into

// Declare variables - some with default values
var _artist = 'Unknown';
var _title = 'Unknown';
var _album = 'Unknown';
var _artworkUrl = 'http://www.mySite.com/Images/MusicNoImage.gif'; // Remote location of no image file
var _isIe = isIe();
var _xmlDoc;

// Purpose
//  Detects if browser is IE
//
// Returns:
//  true if it is.
//
function isIe()
{
    return navigator.appName.indexOf("Microsoft")!=-1;
}

// Purpose:
//  Loads the remote XML file into global variable.
//
function loadXml()
{
    try
    {
        if (window.ActiveXObject)
       {
            _xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
            _xmlDoc.async=false;
            _xmlDoc.onreadystatechange = populateArtistInfoFromXml;
            _xmlDoc.load(REMOTE_XML_URL);
        } else {
            // Opera, Mozilla, Safari & Chrome
            var xmlhttp = new window.XMLHttpRequest();
            xmlhttp.open("GET",REMOTE_XML_URL,false);
            xmlhttp.send(null);
            _xmlDoc = xmlhttp.responseXML.documentElement;
            _xmlDoc.onload=populateArtistInfoFromXml();
            xmlhttp = null;
        }
    }
    catch(e)
    {
        alert(e.message);
    }
}

// Purpose:
//  Populates global fields from global xml doc.
//
function populateArtistInfoFromXml()
{
    try
    {
        if(_xmlDoc != null)
            { 
            if((_xmlDoc.readyState == 4) || (!_isIe))
            {
                //alert('loading values from doc..');       
                if(getNodeValue(_xmlDoc, "title") != null)
                {
                    _title = getNodeValue(_xmlDoc, "title");
                }
                if(getNodeValue(_xmlDoc, "artist") != null)
                {
                    _artist = getNodeValue(_xmlDoc, "artist");
                }
                if(getNodeValue(_xmlDoc, "album") != null)
                {
                    _album = getNodeValue(_xmlDoc, "album");
                }
                if(getNodeValue(_xmlDoc, "image") != null)
                {
                    _artworkUrl = getNodeValue(_xmlDoc, "image");
                }
            }
        }
    }
    catch(e)
    {
        alert(e.message)
    }
}
// Purpose: // Gets and the value from passed in XML document // for the passsed in node name. // // Returns: // value if found or null; // function getNodeValue(xmlDoc, tagName) { var value = null; try { if(_isIe) { value = xmlDoc.getElementsByTagName(tagName)[0].text; // IE } else { value = xmlDoc.getElementsByTagName(tagName)[0].textContent; // Opera, Mozilla, Chrome, Safari } return value; } catch(e) { alert(e.message) } } // Purpose: // Renders the NowPlaying html. // // Inputs: // artist - The artist's name // title - The track name or song title // album - The album name // function renderNowPlaying() { loadXml(); var sb = new StringBuilderEx(); sb.appendFormat("<div id='{0}'>\r\n", OUTER_CONTAINER_IDENTITY); sb.appendFormat(" <div id='{0}' class='{1}' >\r\n", IMAGE_CONTAINER_IDENTITY, IMAGE_CONTAINER_CSS_CLASS); sb.appendFormat(" <img src='{0}' class='{1}' title='{2}' alt='{2}' />\r\n", _artworkUrl, IMAGE_CSS_CLASS, _title); sb.appendFormat(" </div>\r\n"); sb.appendFormat(" <div id='{0}' class='{1}' >\r\n", TEXT_CONTAINER_IDENTITY, TEXT_CONTAINER_CSS_CLASS); if(DISPLAY_ARTIST) { sb.appendFormat(" <p class='{0}' >{1}</p>\r\n", ARTIST_TEXT_CSS_CLASS, _artist); } if(DISPLAY_TITLE) { sb.appendFormat(" <p class='{0}' >{1}</p>\r\n", TITLE_TEXT_CSS_CLASS, _title); } if(DISPLAY_ALBUM) { sb.appendFormat(" <p class='{0}' >{1}</p>\r\n", ALBUM_TEXT_CSS_CLASS, _album); } sb.appendFormat(" </div>\r\n"); sb.appendFormat("</div>\r\n"); var containerDiv = document.getElementById(CONTENT_DIV_ID); containerDiv.innerHTML=sb.toString(); }

You may want to provide a little more error handling and checking for returned null values here and there to.

Html Code

Below is the HTML for the page to display teh now playing infomation. You need to place an empty div in the page and assign it the same ID that you set in the JavaScript constant "CONTENT_DIV_ID". You need to link to the two JavaScript files "StringBuilderEx.js" and "NowPlaying.js". Include a stylesheet to add your own styling and behaviour to the JavaScript created divs Finally call the "renderNowPlaying()" method after the empty div.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Now Playing Test Page</title>
    <link href="StyleSheets/BehaviorStyles.css" rel="stylesheet" type="text/css" />
    <link href="StyleSheets/AppearanceStyles.css" rel="stylesheet" type="text/css" />
    </script src="Javascript/StringBuilderEx.js" type="text/javascript" charset="utf-8">
    </script src="Javascript/NowPlaying.js" type="text/javascript" charset="utf-8">
</head>
<body>
    <div id="StudioInfoContainer" >
        <div id="x"><!-- Now Playing will appear here --></div>
        <script language="javascript" type="text/javascript">
            renderNowPlaying();
        </script>
    </div>
</body>
</html>

Summary

So there you have it a basic web site side implementation of Brandon's Now Playing feature. Feel free to use, alter or extend any of the code in this article.

Compatability

My the 'NowPlaying.js' JavaScript code has been tested and appears to work on the following browsers:

  • IE 6.0.2
  • Opera 9.52
  • Firefox 3.0.5
  • Netscape 9.0b3
  • Safari (Windows) 3.2.1
  • Chrome 1.0

Note

Full implementation of Brandon Fulller's 'Now Playing' iTunes plugin can be found on his website, the link is below.
The JavaScript extended StringBuilder class used in this code is courtesy of Ferreri Gabriele and can be found at the CodePrroject link, below.

Links

Brandon Fuller's Plugin
Ferreri Gabriele's JavaScript StringBuilder

Sunday, February 22, 2009 10:28:09 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] -
Html | JavaScript | iTunes
 Saturday, November 15, 2008

I have recently experienced a JavaScript errror incident when I started using Roles and Membership in a website for the first time.

IE6 reported a syntax error at Line 5 after adding a SiteMapDataSource and Asp.Net Menu controls to the page. The menu would not work I guess due to the JavaScript error.

A quick Google, led me to this page which led me to try adding the following code into my web config

  </system.web>
  
  <!-- Prevent JavaScript Errors, caused by web resource can't be accessed by current user. -->
  <location path="webresource.axd">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location> 

</configuration>

This appeared to remove the error, I am assuming by allowing the web resource JavaScript to be accessed by all users.

 

Saturday, November 15, 2008 10:54:42 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] -
.Net | Asp.Net | Authorization | Config Files | Errors | JavaScript | Membership | Roles
 Thursday, October 30, 2008

Background:

Last night I was doing a little pre-project architecture-checking work, to make sure some ideas I have for my next project will work as anticipated. One part of the web application requires a user to open a popup dialog and edit a value displayed on the main form. There are clearly many solutions to doing this, including posting back the value when submitting, and reloading the parent form when the child form closes. My prefered choice is to acomplish the task in JavaScript.

So first lets create two web pages; Parent.htm and Child.htm.

The Parent Page

In the parent page we are going to add two controls; a pre-populated readonly text box and a button to edit the contents. We will add an "onclick" handler to the button to call a JavaScript method called "editContent()", and we'll add script tags into the head section to place our code. In a real world scenario the JavaScript code would probably be placed in a seperate file.

<html>
<head>
<script language="javascript" type="text/javascript"> <!-- --> </script>
</head>
<body> <form> <input type="text" name="txtEditValue" id="txtEditValue" value="Original content" readonly="readonly" > <input type="submit" name="btnEdit" id="btnEdit" value="Edit" onClick="editContent();" > </form> </body> </html>

In the script section we need to add some JavaScript to open the Child window. First we'll declare a global variable to hold a reference to the window in case we need it later (Possibly in a later article about Modal child forms which will use this code!).

var m_childWindow = null;

Now we wil create the "editContent()" method which will be called from the button "onClick" handler. For the moment the "editContent()" method just calls through to the "openWindow()" method. This may seem a bit of a waste of code, but my reason for it is for program flow code reading clarrity.  The edit button (btnEdit) calls the "editContent()" method, named as it relates directly to the action the user has performed. If I had plugged btnEdit's onclick into the "openWindow()" method it would not be so logical to follow program flow. I guess using this methodalogy a better name for the "editContent()" method would have been "btnEdit_OnClick()", but hell it is just an artical on my blog, not something going into productions, so why am I tying my self up in knots over this?

The "openWindow()" method just opens a new window and assignes a reference to it top our global variable. The first parameter is teh url for the child page, the second the window name, and the third contains the properties for the window; height, width, whether to display menu bar, etc.

function editContent()
{
    openWindow();
}

function openWindow()
{
    var newWin = null;
    newWin = window.open ('Child.htm', 'childWindow', 'menubar=0,resizable=0,status=1,width=350,height=250');
    m_childWindow = newWin;
}

We now need two methods to act as accessors for the text box value; one to get and one to set.

function getEditValue()
{
    var editTextBox;    
    editTextBox = document.getElementById("txtEditValue");
    return editTextBox.value;
}
function setEditValue(value)
{
    var editTextBox;    
    editTextBox = document.getElementById("txtEditValue");
    editTextBox.value = value;
}

The Child Page

Now we'll move on to creating the child page. This will also have two controls; a TextBox and a Button. The text box will be used by the user to edit the value, and the button to submit changes back to the parent form.

<html>
<head>
<script language="javascript" type="text/javascript">
<!--

-->
</script>
</head>
<body onload="bodyOnLoad()"  >
    <form >
        <input type="text" name="txtEditValue" id="txtEditValue">
        <input type="submit" name="btnSubmit" id="btnSubmit" value="Save" onClick="submitForm();" >
    </form>
</body>
</html>

You will hopefully have noticed that the body onload event calls a JavaScript method called "bodyOnLoad()", so we had better create this first. The "bodyOnLoad()" method purely calls the "populateTextBox()" method via JavaScript's own "setTimeout()" method, with a quarter second delay.

function bodyOnLoad()
{
    setTimeout ( "populateTextBox()", 250 );
}

I have used the "setTimeout()" method purely becuase in tests with the Opera browser the window.opener property is not populated in time for aour call to access it in the "populateTextBox()" method. However, in Internet Explorer and Firefox, this was not the case. I presume the reason for needing this delay is to allow Opera to finish building the DOM tree. (Any one have any info on this?)

function populateTextBox()
{
    var editTextBox = null;    
    editTextBox = document.getElementById('txtEditValue');
    
    var windowOpener = null;
    windowOpener = window.opener;
    
    if(windowOpener==undefined)
    {
        alert('No opener');
    }
    else
    {
        if(editTextBox != null)
        {
            editTextBox.value = windowOpener.getEditValue();
        }
    }
}

The "populateTextBox()" method declares two variables, one to hold a reference to the TextBox and the other a reference to the window.opener object. In this case we are assuming that the window.opener will always be our Parent.htm page and will have the "getEditValue()" method available. Obviously in a real world example this should be guarded against. So in essence once the page is loaded, the text box is populated by reading the value returned from the window.opener's "getEditValue()" method.

Editing and saving the value.

Once the value is in the text box the user is free to edit the value, and can then click the save button to call a method to send the value back to the parent form and close the child window.

function submitForm()
{
    var windowOpener = null;
    windowOpener = window.opener;

    var editTextBox = null;    
    editTextBox = document.getElementById("txtEditValue");

    windowOpener.setEditValue( editTextBox.value);
    window.close();
}

So the "submitForm()" method declares two variables to hold references to the TextBox and window opener again, and uses the window.opener's "setEditValue(value)" method to pass back the changed value to the parent form. Then the child form is closed.

Summary

So there you have it a simple JavaScript based solution for editing a value of a parent form from within a child form. My intention for my future project is to embed a RichTextEdit in the child form, and only display the finished HTML in an IFRAME on the parent form. Hopefully this will help someone who is looking to do a similar thing!

Please note through out this example error trapping and defensive coding has been ommitted for clarrity. it would also be preferable for the child page to be a modal window. I will hopefully look into a solution for that a little later.

Thursday, October 30, 2008 7:00:05 AM (GMT Standard Time, UTC+00:00)  #    Comments [1] -
Html | JavaScript
Archive
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910
Blogroll
 Clemens Vasters
 Harry Pierson
Passion * Technology * Ruthless Competence
 Joshua Flanagan
A .NET Software Developer
 Michael Schwarz's Blog
Developing applications on the Microsoft platform since Windows 3.1!
 Omar Shahine
Yet another Microsoft blogger
 Scot GU
Scott Guthrie lives in Seattle and builds a few products for Microsoft
 Scott Hanselman
Programming Life and the Zen of Computers
 Tom Mertens
Tom's corner
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Duane Wingett
Sign In
Statistics
Total Posts: 26
This Year: 0
This Month: 0
This Week: 0
Comments: 28
Themes
Pick a theme:
All Content © 2010, Duane Wingett
DasBlog theme 'Business' created by Christoph De Baene (delarou)