How We Did It - DZone Available On Your iPhone
Join the DZone community and get the full member experience.
Join For FreeThe iPhone has been all the rage lately, from complaints to praise it has all been heard. Whether you hate it or love it, the fact remains, as a developer you cannot ignore it. And here at DZone we could not ignore the chance to provide even more means by which you can access your development links. In this article I will share with you how we went about recreating DZone for the iPhone.
First things first, get your development environment set-up. I chose to go with an old favorite, Aptana Studio. After you have downloaded Aptana go ahead and install the iPhone development tools which you will find available from the studio's welcome page. After all of the components have been downloaded, select install all and restart your workbench. You are now all set to start building your first iPhone app.
Next, click on File > New Project and then select the iPhone project. Give your project a name and you will next be presented with an option screen to import some JavaScript libraries. For theDZone project we decided to go with iUI but feel free to choose which ever libraries you feel comfortable with. When you click finish you will see that Aptana starts to create your project. Once completed you will be presented with a base HTML page that contains some CSS and JavaScript. This is a good starting point and will give you a feel for the new tools. You will also notice that at the bottom of the screen where you used to have source, Firefox and IE, you now have a new tab entitled iPhone. With the HTML page still open, click on the iPhone tab to see an emulation of how your page will look once viewed on the iPhone.
You will also notice that when you click on any of the black empty areas around the iPhone the phone will rotate and your layout will also dynamically change. This layout change is not automatic but is made possible by a small script that was added to the page automatically byAptana, it looks as follows:
addEventListener("load", function(){
setTimeout(updateLayout, 0);
}, false);
var currentWidth = 0;
function updateLayout(){
if (window.innerWidth != currentWidth) {
currentWidth = window.innerWidth;
var orient = currentWidth == 320 ? "profile" : "landscape";
document.body.setAttribute("orient", orient);
setTimeout(function(){
window.scrollTo(0, 1);
}, 100);
}
}
setInterval(updateLayout, 1400);
console.info('iPhone logging initialized');
After I completed playing around with the new tools and seeing how the emulator works I decided the
first thing I want to do is to separate the structure from the style and the presentation, I would
certainly suggest you do the same, it just makes for a much more maintainable application in the long
run. My first step was to move the CSS embedded in the page out into it's own file. I created a new
folder called, you guessed it CSS, and created a new CSS file and called it screen.css. I next copied all
of the CSS from the HTML page and pasted it into the CSS file. The last step here was to include the
CSS file in the HTML page. So you need to add the following tag to the HTML page.
<style type="text/css" media="screen">@import "/css/iphone.css";</style>
Next, leave the following line on the page:
<script type="text/javascript" src="lib/firebug/firebug.js"></script>
But then, create a new folder called js and a new JavaScript file entitled updateLayout.js. Next go ahead and copy the script and save. Back on the HTML page, you need to add a tag to include this new JavaScript file we just created. Add the following:
<script type="text/javascript" src="js/updateLayout.js"></script>
To make sure that everything still works as before, click on the iPhone tab. Everything should still look and work the same, Now that we have the stage set, let's get started putting this iPhone version of DZone together. There are a few sites that has been the choice of so many is because it makes it much simpler to create webapps for the iPhone that feels a lot more • Create Navigational Menus and iPhone interfaces from standard HTML
- Use or knowledge of JavaScript is not required to create basic iPhone pages
- Ability to handle phone orientation changes
- Provide a more "iPhone-like" experience to Web apps (on or off the iPhone)
To enable us to start using iUI we need to include two files in the head section of our document. So go ahead and add the following:
<style type="text/css" media="screen">@import "lib/iUI/iui.css";</style>
<script type="application/x-javascript" src="lib/iUI/iui.js"></script>
With that added we are ready to start building our interface. Before we start coding our interface, let's add one more thing to our head section:
<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
The iUI library uses a couple of naming conventions that makes the scripting and style rules kick in. The first we will look at is the toolbar. Inside the body tag add the following:
<div class="toolbar"></div>
If you now click on the iphone tab within Aptana you will see a bar added to the top of the emulator screen:
[img_assist|nid=4543|title=|desc=|link=none|align=none|width=300|height=272]
That is the default styling provided by the iUI library for the the toolbar CSS class. That was not exactly what we were after so we had to over rule that style rule inside our own iphone.css file. With this said, it now becomes important that the order of the included style sheets are correct. As we know the cascade of CSS works from top to bottom, external to inline so, it is important that you include the style sheets as follows:
<style type="text/css" media="screen">@import "lib/iUI/iui.css";</style>
<style type="text/css" media="screen">@import "css/iphone.css";</style>
That way, any style rule by the same name will override what was defined in iui.css. To get the feel we were after we changed the styling of toolbar as follows:
body > .toolbar
{
background-color:#3366aa;
background-image:none;
box-sizing:border-box;
-moz-box-sizing:border-box;
border-bottom:1px solid #fff;
border-top:1px solid #000;
padding:10px;
height:25px;
}
After you added this style rule to the CSS file go ahead and revisit the iphone tab. You should now see the following:
[img_assist|nid=4544|title=|desc=|link=none|align=none|width=300|height=240]
Now we need to add some items to out toolbar. Let's add the DZone logo onto the toolbar. To do this we added the following line inside the toolbar div:
<div class="toolbar">
<a href="/iphone"><h1 id="pageTitle"></h1></a>
<div>
To the H1 we added an id called pageTitle and applied the following style rule:
#pageTitle
{
background:transparent url('../media/DZone-iphone-137x30.png') top left no-repeat;
margin:0;
padding:0;
background-position:0 0;
height:30px;
}
Now if you click on the iphone tab in Aptana you will find no difference. Why is this? Unfortunately I have no idea other then that the emulator does not do the best job and I needed to find an alternative approach.
Being on Windows I did not have the option of installing the iPhone SDK from Apple as this is currently only available on Mac so, short of installing VirtualBox and running the Mac operating system inside it,
I had to find another alternative. As Safari is the browser that runs on the iPhone and with Safari now being available on Windows, I switched to using the Safari browser for further testing.
However, I need to see what the layout looked like in the same aspect ratio of the iPhone screen size so I searched for a web based iPhone emulator. I found iPhoneTester.com and for the most part it worked
rather well but, I could not really be sure that what this emulator showed me was accurate. Luckily a fellow developer working with me on this project had a Mac and installed the iPhone SDK. The situation was not
ideal though as we were working remotely so I had to send him a zip of the work I have done and he had to send me screen shots and feedback on what he was seeing.
With Safari on Windows, at this point I have to rant a little bit and ask Why oh Why Apple, do we not have an iPhone SDK for Windows. With my rant aside, this is the route we followed from here on. I would preview the app in Safari on Windows and send him the code to verify whether what I was seeing was what users would see using an iPhone. But we have another problem, simply viewing the app in Safari is not enough as the viewport size of a browser on the desktop and the viewport on the actual iPhone differs greately.
The kind folks at Manning Publishing has given us a chapter to offer to readers of this article for free. The chapter is from the yet unpublished book iPhone in Action to be published December 2008. Download SDK Programming for Web Developers
To overcome this, I again loaded up iPhoneTester.com and resized my Safari browser to be the same size as the emulator screen real estate.
[img_assist|nid=4545|title=|desc=|link=none|align=none|width=300|height=437]
Ok, so now we have a home grown iPhone SDK on Windows that might not be 100% accurate but gives us a basic idea of what to expect and hopefully less round robin with my fellow developer that has the real SDK installed. With our environment set-up let's add two more elements to our toolbar. Next we add a login link to our toolbar that will launch a dialog where users can log in. So inside your toolbar div add:
<a class="login" href="login.html">Login</a>
After adding the CSS below to you stylesheet refresh Safari to see our new login link added:
.login
{
position:absolute;
top:0;
right:5px;
-webkit-border-radius:0;
border-width:0 5px 0 5px;
padding:6px 10px;
height:28px;
line-height:28px;
font-size:14px;
font-weight:bold;
color:#fff;
text-shadow:rgba(0, 0, 0, 0.6) 0px -1px 0;
text-decoration:none;
background:none;
}
Go ahead and click on the login link. You should be presented with this:
[img_assist|nid=4546|title=|desc=|link=none|align=none|width=300|height=339]
Wow! Now here you see some of the magic of iUI, a really nice iPhone style dialog popping up. One thing you might be thinking is, where does the form come from. Well, you need to create and link to it.
If you look back at the line we added for the login link you will see it links to a page called login.html. Here it is:
<form id="loginForm" class="dialog" method="post" action="/login">
<fieldset>
<h1>Login</h1>
<label class="inside" id="username-label" for="username">
Username...
</label>
<input type="text" id="username" name="side-username" />
<label class="inside" id="password-label" for="password">
Password...
</label>
<input type="password" id="password" name="side-password" /><input class="submitButton" type="submit" value="Login" /><input type="hidden" name="processlogin" value="1" /><input type="hidden" name="returnpage" value="/iphone" />
</fieldset>
</form>
One important point. The login.html page contains exactly what is presented above, nothing more, nothing less. When you click into the username or password fields you will see that the background text stays right there. No worries, we will take of that a little later. For now, let's move on and add another item to the toolbar. As there is various categories/tags that links are posted as we want the user to be able to narrow their view to the only items categories they are interested in. So next we add the category link to the toolbar. To this we add one more line to our toolbar div to end up with:
<div class="toolbar">
<a href="/iphone"><h1 id="pageTitle"></h1></a>
<a class="showPage login" href="login.html">Login</a>
<a class="showPage tags" href="categories.html">Tags</a>
<div>
Here we add a class called tags to position our new link where we want it. To do this add the following to you CSS file:
.toolbar .tags {
position: absolute;
top: 0;
right:65px;
-webkit-border-radius: 0;
border-width: 0 5px 0 5px;
padding: 6px 10px;
height: 28px;
line-height: 28px;
font-size: 14px;
font-weight: bold;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.6) 0px -1px 0;
text-decoration: none;
background: none;
}
Go ahead and refresh Safari but, before you click on the link create a HTML page called categories.html and add the following code to it:
<form id="categoryForm" class="dialog" method="get" action="/iphone">
<fieldset>
<h1>Tags</h1>
<select id="topic" name="topic">
<option value="all" selected="selected">All Stories</option>
<option value="technology">Technology</option>
<option value="apple">Apple</option>
<option value="design">Design</option>
<option value="gadgets">Gadgets</option>
<option value="hardware">Hardware</option>
<option value="tech_news">Tech Industry News</option>
<option value="linux_unix">Linux/Unix</option>
<option value="microsoft">Microsoft</option>
<option value="mods">Mods</option>
<option value="programming">Programming</option>
<option value="security">Security</option>
</select>
<input class="submitButton" type="submit" value="Go" />
</fieldset>
</form>
Of course this is all hard coded and you might want to hook this up to your back-end solution to have the options dynamically generated. Now go ahead and click on the 'Tags' link. As with the login form you see a dialog launch:
[img_assist|nid=4553|title=|desc=|link=none|align=none|width=300|height=436]
By the way, if you are new to this you may wonder, now how do I get rid of the dialog? Easy, clicking on any part of the dark area outside the dialog will take you out of dialog mode. So now that we have out toolbar complete we need to start working on the content area of the app. We basically want to display the list of links in the popular queue you would see when you go to dzone.com with your desktop browser. Because of screen size we have to however limit the amount of links per page and instead of the 'endless scrolling' used on DZone we needed to implement pagination between each set of links.
To start building our content add the following to your index.html file after the closing div of our toolbar:
<ul id="stories" selected="true">
<li>
<a href="#6983724" class="zone-count">141</a>
<a href="#6983724" class="link">Redefining Anti-Virus Software</a>
</li>
</ul>
After adding this go ahead and refresh the browser. You should see the following:
[img_assist|nid=4548|title=|desc=|link=none|align=none|width=300|height=238]
This is the basic styling that the iUI toolkit applies to unordered lists. As mentioned before this reflects the native look and feel of other apps on the iPhone. The basics of this is fine but we needed to fine tune this a bit for our needs. First stop is to override the style applied by iUI for links inside an list item. Add the following to your iphone.css file:
body > ul > li > a
{
display: block;
margin: -8px 0 -8px -10px;
padding: 8px 32px 8px 15px;
text-decoration: none;
color: inherit;
font-size:70%;
background: url(../lib/iUI/listArrow.png) no-repeat right center;
height:30px;
}
That changes our link text size to a more manageable size and allows us to add more links per page as we would have been able to with the larger text size. Next we need to add the style rules for our zone-count class:
li .zone-count
{
background:transparent url('http://dzone.com//links/themes/iphone/media/vwidget2_bkgd_on.gif') top left no-repeat;
color:#000;
float:left;
margin-right:3px;
padding-top:7px;
text-align:center;
font-size:70%;
font-weight: bold;
text-decoration: none;
width:29px;
height:40px;
}
NOTE: If you are following this article using the iPhone SDK on Mac, you may need to adjust the pixel dimensions slightly as Safari on the desktop does not render the items exactly the same as Safari on the iPhone. This was one of the headaches we had to cope with as I was doing the front end on Windows and did not have access to the SDK.
Next let's fix up the link text so that it lines up better with our zone counter block. Change the style rule for links in list items to the following:
body > ul > li > a
{
display: block;
padding: 15px 32px 8px 15px;
text-decoration: none;
color: inherit;
font-size:70%;
background: url(../lib/iUI/listArrow.png) no-repeat right center;
height:23px;
}
Also go ahead and inside your HTML file create around five copies of the current list item. Go ahead and refresh your browser, you should see the following:
[img_assist|nid=4549|title=|desc=|link=none|align=none|width=300|height=336]
Now that does not look bad at all. Before we move on to transitioning to the story page, let's add the pagination I spoke of earlier. Add the following to the end our current unordered list:
<li class="pagination">
<a class="next" target="_self" href="?p=2">Page 2</a>
</li>
If you refresh your browser now, you will see at the bottom we have another item added to our list with the same style as the other links except without the zone counter. However, we decided that we wanted to style this a little different and make it stand out more. We will also not only need a next page link but also a previous. With that said add the following to the list item we just added:
<a class="previous" target="_self" href="?p=1" class="next">Page 1</a>
Your pagination list should now look like this:
<li class="pagination">
<a class="previous" target="_self" href="?p=1" class="next">Page 1</a>
<a class="next" target="_self" href="?p=2">Page 2</a>
</li>
Now we need to style these two elements and float the one to the left of the screen and the other to the right. For our container pagination list item we need the following style rule to add some breathing
space as well as remove the bottom border that will be added by default due to the list item rule we defined earlier:
body > ul > li.pagination
{
position: relative;
margin:5px 0;
border-bottom:none;
padding: 8px 0 8px 10px;
font-size: 20px;
font-weight: bold;
list-style: none;
}
For the previous link we need to add the following to our CSS file:
.previous
{
float:left;
background:transparent url('http://dzone.com//links/themes/iphone/media/nav_left_blue_36.png') top left no-repeat;
margin-left:5px;
padding:6px 5px 0 40px;
font-size:110%;
height:36px;
}
And for our next button we need the following:
.next
{
float:right;
background:transparent url('http://dzone.com/links/themes/iphone/media/nav_right_blue_36.png') top right no-repeat;
margin-right:15px;
padding:6px 45px 0 5px;
font-size:110%;
height:36px;
}
With all that added refresh your browser and you should see the following:
[img_assist|nid=4550|title=|desc=|link=none|align=none|width=300|height=437]
With that our landing page is done and we can move on to the story page. One thing to note here is that you will see we made the previous and next images as well as text much larger then the link text.
The reason for this is simply to make it easier for users to interact with the interface by giving a larger hit area then would have been available had we made the icons and text as small as the links. The
links automatically provide a larger hit area as the entire line in width and height is clickable.
Now lets add a story. Initially we created a story.html page and linked to that page to display the content of a story but, in the end we decided to move back to the one page style that most other iPhonized sites
have stuck to. We might change this as the development moves forward or it might not. Anyhow, for the purposes of this article I will stick to the one page concept. Inside your index.html after the closing unordered list tag add the following:
<div id="103776" title="">
<div class="story-body">
<h3><a target="_self" href="http://timeago.yarp.com/">timeago: a jQuery plugin</a></h3>
<p class="details">Timeago is a jQuery plugin that makes it easy to support automatically updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").</p>
</div>
</div>
Make sure that the href of your links link to #103776 to ensure your links work as expected. Go ahead I know you want to. Click on one of the links and see what happens. Pretty awesome I think, I nice sliding transition effect thanks to iUI. Before we add our styling for the story page let's look at how exactly this transition works. At line 150 of the iui.js file located in lib > iUI you will see the following line:
addEventListener("click", function(event)
So here is where the event listener is added for click events such as when you clicked on the link. When the click happened this listener was notified and it sprung into action. The first thing we need is the hash of the current node that initiated the click event:
var link = findParent(event.target, "a");
Here we assign the value returned by the function 'findParent' to the variable link. This is how the function looks:
function findParent(node, localName)
{
while (node && (node.nodeType != 1 || node.localName.toLowerCase() != localName))
node = node.parentNode;
return node;
}
When we enter this function from the click event that resulted from the anchor link, the first check in the while loop will pass but, our current nodeType is 1 and as our localName is "a" so both conditions inside the brackets will fail causing the script to jump out of the while loop and simply return the node and assign this to the var link. Next we jump over the first if statement but move into the second:
if (link.href && link.hash && link.hash != "#")
{
link.setAttribute("selected", "true");
iui.showPage($(link.hash.substr(1)));
setTimeout(unselect, 500);
}
The fist thing this script does is set the value of the 'selected' attribute to true. If you are stepping through this script you will see that after this line has executed the background color of the link changes to blue. The next line calls the function that creates the sliding transition effect. We call the showPage function passing in the element we are linking from. We call a little utility function to retrieve this element for us based on the id. So in our case we are doing the following:
iui.showPage($(103776));
The utility function looks like this and is pretty self explanatory:
function $(id) { return document.getElementById(id); }
This will then return our DIV that contains the story we are linking to. Next we pass this showPage function listed below:
showPage: function(page, backwards)
{
if (page)
{
if (currentDialog)
{
currentDialog.removeAttribute("selected");
currentDialog = null;
}
if (hasClass(page, "dialog"))
showDialog(page);
else
{
var fromPage = currentPage;
currentPage = page;
if (fromPage)
setTimeout(slidePages, 0, fromPage, page, backwards);
else
updatePage(page, fromPage);
}
}
}
When we enter the script here 'backwards' will be undefined and 'page' will contain the content of our DIV. Our first condition passes and we step into the condition block and the next conditional statement. If you look at the top of the uiu.js file you will see that 'currentDialog' is initialized to null and, as we are not triggering a dialog here, this is what it will still be so this condition will fail and we will move to the next condition. This condition will again fail as our current node does not contain a class with the name 'dialog', with that, we step into the else.
As we move into the else block the script's first task is to initialize the variable 'fromPage' with the value of 'currentPage'. Next we overwrite the value of currentPage with the value of our story page. The script next checks whether fromPage is null and if not moves into the setTimeout function calling the slidePages function. Because the call to setTimeout is called with a 0 millisecond wait time the slidePages script will wait to execute until the current call stack has completed it's execution. So from here we return to event listener and the following line is executed:
setTimeout(unselect, 500);
The unselect function looks as follows:
function unselect() { link.removeAttribute("selected"); }
So after a 500 millisecond wait, the unselect function will remove our 'selected' attribute and call the following function to stop the default action the browser would have taken for this event:
event.preventDefault();
Having left the event handler the function that will check whether the orientation and/or location has changed and make the needed changes is called. This utility function looks as follows:
function checkOrientAndLocation()
{
if (window.innerWidth != currentWidth)
{
currentWidth = window.innerWidth;
var orient = currentWidth == 320 ? "profile" : "landscape";
document.body.setAttribute("orient", orient);
setTimeout(scrollTo, 100, 0, 1);
}
if (location.hash != currentHash)
{
var pageId = location.hash.substr(hashPrefix.length)
iui.showPageById(pageId);
}
}
For our current scenario both conditional blocks are skipped and the the checkOrientAndLocation function is exited without executing any of the code. When we exit this code block the current call stack is complete and the slidePages function and execute, this is what that function looks like:
function slidePages(fromPage, toPage, backwards)
{
var axis = (backwards ? fromPage : toPage).getAttribute("axis");
if (axis == "y")
(backwards ? fromPage : toPage).style.top = "100%";
else
toPage.style.left = "100%";
toPage.setAttribute("selected", "true");
scrollTo(0, 1);
clearInterval(checkTimer);
var percent = 100;
slide();
var timer = setInterval(slide, slideInterval);
function slide()
{
percent -= slideSpeed;
if (percent <= 0)
{
percent = 0;
if (!hasClass(toPage, "dialog"))
fromPage.removeAttribute("selected");
clearInterval(timer);
checkTimer = setInterval(checkOrientAndLocation, 300);
setTimeout(updatePage, 0, toPage, fromPage);
}
if (axis == "y")
{
backwards
? fromPage.style.top = (100-percent) + "%"
: toPage.style.top = percent + "%";
}
else
{
fromPage.style.left = (backwards ? (100-percent) : (percent-100)) + "%";
toPage.style.left = (backwards ? -percent : percent) + "%";
}
}
}
This is then finally the script that is going to cause the nice transition effect of sliding in our new content instead of either loading the new page or, in our case, jumping to the content as would normally be the case with anchor links. After the first line has executed the var axis is equal to null. This means that our first conditional block will be skipped as 'axis' does not equal 'y', instead 'toPage' which is our story DIV, is given a left position that is 100% from the left of our screen. This will place our DIV just of screen to the right of our link list. The content is given the selected attribute and is set to true after which the content is scrolled up to get it into position for the transition.
When the document was loaded initially we called the checkOrientAndLocation function using setTimeout and assigned the id for this timer to the variable checkTimer, we now use this id to clear that timers interval and prevent the timer from triggering the execution of the script. Next we initialize 'percent' to equal 100 and call the slide() function. The slide function does basically two things for us, with each iteration it decreases the value of percent by 20% and increases the style.left set on 'fromPage' by 20%. This means that after five iteration we would have swapped the links with the story content. One thing to not is that after out first iteration we start a timer to execute the slide function with a wait time of 0, remember what this means.
The last time we execute the slide method and percent is equal to 0 we execute this block:
if (percent <= 0)
{
percent = 0;
if (!hasClass(toPage, "dialog"))
fromPage.removeAttribute("selected");
clearInterval(timer);
checkTimer = setInterval(checkOrientAndLocation, 300);
setTimeout(updatePage, 0, toPage, fromPage);
}
There is some really clever stuff happening here. So, the first thing that iUI does for us after so gracefully sliding the stories content into place is stop the timer that was executing the slide function. Next it re-initializes the checkOrientAndLocation function to execute every 300 milliseconds and saves the id on the checkTimer variable. Finally it starts a new timer calling the updatePage function with a 0 second wait time. So again as before, remember what this means, the current executing stack will complete after which the updatePage function will be executed. When update page is executed this is the code that runs:
function updatePage(page, fromPage)
{
if (!page.id)
page.id = "__" + (++newPageCount) + "__";
location.href = currentHash = hashPrefix + page.id;
pageHistory.push(page.id);
var pageTitle = $("pageTitle");
if (page.title)
pageTitle.innerHTML = page.title;
if (page.localName.toLowerCase() == "form" && !page.target)
showForm(page);
var backButton = $("backButton");
if (backButton)
{
var prevPage = $(pageHistory[pageHistory.length-2]);
if (prevPage && !page.getAttribute("hideBackButton"))
{
backButton.style.display = "inline";
backButton.innerHTML = prevPage.title ? prevPage.title : "Back";
}
else
backButton.style.display = "none";
}
}
Another reason for using iUI is that it assists us in keeping our history intact and allows users to freely use the back button on the phone for navigation purposes if no other means are provided or the user simply prefers this. And it is in updatePage where this happens. The first thing that it does in our case is update the href in the location bar to #_ and the id of our current page, which is currently is 103776. Next is adds this page id to the pageHistory[]. It will then look for a id of pageTitle and set the new document's title to the value of the title of this element or skip this if there is no element with such an id or it is empty. And that is it, the rest is skipped as we are not working with a form or using a link with an id of backButton.
Now that we have our content sliding into view when we click on a link we need to style our content and add some additional fields and a back link to return to our links. First let's style the content already present. Add the following to your CSS style sheet to style the H3 and the paragraph:
.story-body h3
{
margin:10px auto 7px 10px;
font-size:22px;
line-height:1em;
}
.story-body h3 a
{
margin:0;
padding:0;
text-decoration:none;
}
.details, .details p
{
margin:0;
margin-left:10px;
padding:0 5px 10px 0;
font-size:90%;
line-height:140%;
}
Next let's add some more details about the post such as the date, views, submitter etc. For that we will use an unordered list so add the following to the story body DIV:
<ul class="news-details">
<li>Published: Aug 16 / 11:44.</li>
<li>Views: 327, Clicks: 161, Score: 21.1</li>
<li>Via: <a href="/links/search.html?query=domain:timeago.yarp.com">timeago.yarp.com</a></li>
<li>Tags: <a href="/links/iphone?t=frameworks" target="_self" class="tags" rel="tag">frameworks</a>, <a href="/links/iphone?t=javascript" target="_self" class="tags" rel="tag">javascript</a></li>
<li>Submitter: <a class="user" href="/links/users/profile/111696.html">bloid</a></li>
</ul>
And the following to your CSS file to style our list:
.news-details
{
background-color:#fff;
color:#666;
margin:15px 0 0 10px;
padding:0;
font-size:12px;
line-height:150%;
list-style-type:none;
}
If you now go back to the story and reload it you should see something similar to the following:
[img_assist|nid=4551|title=|desc=|link=none|align=none|width=300|height=326]
Looking good! We still need to add our back button to this screen so, let's go ahead and do that now. After the closing DIV tag for story-body but before the final closing DIV add the following:
<p><a href="#stories" target="_self" class="previous">Back to Links</a></p>
No need to anything else, the style has already been added earlier when we added the previous link to our pagination navigation elements. Before I close of this article I want to point you to something. Click on the login link again and then click inside the text field to add your username and/or password. What is wrong here? Yip, the insert point is almost half way down the length of the text area and the 'background' text does not go away when clicking or even typing in this box. Let's solve these issues and while we are at it, let's tighten up the look and feel of both our dialogs.
Add the following styles for the fieldset and the H1 inside out fieldset:
fieldset
{
box-sizing:border-box;
width:100%;
margin:0;
border:none;
padding:10px 6px;
background-color:#7388a5;
}
fieldset > h1 {
margin: 0 10px 0 10px;
padding: 0;
font-size: 20px;
font-weight: bold;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.6) 0px -1px 0;
text-align: center;
}
To take care of our labels and input boxes we need to following CSS:
label
{
font-size: 14px;
text-align: left;
display: block;
margin: 5px 0 2px 4px;
font-weight: bold;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.6) 0px -1px 0;
}
label.inside
{
position: absolute;
margin: 14px 0 0 15px;
color: #BBB;
text-shadow: none;
}
input[type='text'], input[type='password']
{
width:95%;
font-size: 16px;
}
input
{
padding:5px 0 5px 3px;
box-sizing: border-box;
margin-right:20px;
font-size: 17px;
font-weight: normal;
}
At this point you can go ahead and refresh the browser and test out the login input boxes. Much better right? The background text is still there though, we will take care of that in a second. Let's refine the rest of the dialog elements. For the bottons and the select drop down add the following to your CSS file:
select
{
margin-right:20px;
width:90%;
font-size:16px;
}
input[type='submit']
{
float: right;
margin-top: 0;
margin-right: 20px;
width:100px;
}
Your dialog should no look a ton better and resemble the following screen: (remember if you are using an actual iPhone or the SDK on Mac, you may need to tweak some of the dimensions to get the same result)
[img_assist|nid=4547|title=|desc=|link=none|align=none|width=300|height=267]
Only one thing left, get rid of that annoying background text inside the username and password fields. For this we add some jQuery goodness. Create a new file inside the js folder and name it iphone.js. Add the following code snippet to this file and hit save:
$(document).ready(function(){
$('#username, #password').focus(function(){
$('#' + $(this).attr('id') + '-label').hide();
})
});
Now in the head of the index.html page add the following to add the JavaScript file to our page:
<script type="application/x-javascript" src="js/iphone.js"></script>
If you do not have jQuery yet, then go ahead and download jQuery, save the file to the js folder and add the following to the head just before the iphone.js line:
<script type="application/x-javascript" src="js/jquery.js"></script>
Now go ahead and refresh the browser, launch the log in dialog and test out those form elements. What? It still does not go away? Not to worry there are two small things we have to change to our current set-up to get this to work. In the toolbar section of the index.html page change the link to the login form as follows:
<a class="login" href="#loginForm">Login</a>
Copy the code from the login.html file to the index.html just after the closing DIV of the story. Save everything and refresh the browser again. This time when you click inside the username or password fields the background text goes away. And that is it! That is how we got DZone on the iPhone. There are still some enhancements we would like to make and this article does not cover how the back-end was hooked up to this interface but I am sure most of you can figure that one out as there should not be to much of a difference, if any, then the way you are currently doing it with your desktop browser based apps. I hope you enjoyed this article, found it useful, learned something new and will start building your own versions for the iPhone using iUI. We encourage you to use the iPhone version of DZone at http://dzone.com/iphone and send us you feedback on how we can improve on what we already have and what you would
like to see in future versions.
Opinions expressed by DZone contributors are their own.
Comments