BlogBlog

Posts tagged with: CSS3

Head Above Water

Friday, April 4, 2014 6:31 PM

NOVCollageWow. I was just looking and realized it has been almost 5 months since I last posted here. I’ve been really heads down on a project for National Oilwell Varco that we just delivered last Friday for their initial beta testing. The app is pretty amazing. It is used to visualize oil well designs in 2D and 3D and is built in pure HTML5 and CSS3 using HTML5 canvas for all of the visualizations and drag-drop interactivity. The app was built with AngularJS, KineticJS, ThreeJS, marking my first extensive use of all three of these libraries and had a back-end based on ASP.NET Web API. It’s the first line-of-business app that I’ve seen that makes extensive use of HTML5 canvas and I will definitely have more to say about this in the near future.

As for now, I’m just glad to be able to come up for air and catch up on everything else for a while.

 
By: shane
Comments

Comments

Be the first to comment on this post

Review - Using PhoneGap Build Beta

Wednesday, September 5, 2012 1:28 PM

Adobe PhoneGap Build BetaMy most recent blog post on the EffectiveUI Blog just went live. The post is a review of my experiences using the PhoneGap Build beta for an iPad prototype.

Recently I was asked to build a prototype for a sales proposal here at EffectiveUI to enable the client to see what the finished design would behave like on a real iPad. We had provided an initial demo to the client through FieldTest; however, they wanted to see examples of what the actual interactivity would look and feel like on a real device. The client also added an additional requirement that the prototype be able to work completely offline. The eventual architecture for this application was to be a hybrid mobile Web and native application, much like I described in this MSDN Magazine article and in this blog post. …

Read the rest of the post at the EffectiveUI Blog.

 
By: Shane
Comments

Comments

Be the first to comment on this post

Building a Responsive Design

Thursday, August 2, 2012 1:11 PM

Mobile LayoutOne of the most interesting things I found looking at my web traffic reports for this site following the publication of my article, “Develop Hybrid Native and Mobile Web Apps” in the March 2012 issue of MSDN Magazine was how many iPad browsers were accessing the site. Not surprisingly given my background as a Microsoft developer, my statistics were dominated by Internet Explorer but the iPad, iPhone, and Android platforms accounted for approximately 13% of the unique visits to my site. Knowing that my site was designed for primarily desktop browsers, I immediately wondered what the site might look like to those users and how usable it might be. The short answer to those questions was: It looked awful and was completely unusable!

In the US, there were 250 million mobile phones and 100 million smartphones at the end of 2011. While most of the focus for mobile development was here given the scale, product strategy professionals also turned their attention to tablets (33.7 million) and eReaders (25.1 million) according to Forrester Research Consumer PC And Tablet Forecast, 2011 To 2016 (US) and Forrester Research eReader Adoption Forecast, 2011 To 2016 (US) respectively. At EffectiveUI, one of the big trends that we are seeing is a rapid shift away from traditional desktop browsing experience to a multimodal experience encompassing smartphones, tablets, laptops, and traditional desktops. Given these multimodal requirements, developers are faced with a choice of building tailored experiences for each viewing platform or building a responsive design that smoothly accommodates a wide range of devices. I’ve talked in the past in my post on the EffectiveUI Blog, “Mobile Web, Hybrid, or Native Mobile – How Do You Choose?”, about the decision process for choosing to build a Mobile Web, Hybrid, or Native Mobile application and the decision tree for choosing a responsive design or platform specific designs is very similar.

Because of the fact that this site is largely intended for reading and is not a particularly interactive application, the responsive design option was the obvious choice to me. Responsive design uses CSS media queries in order to rearrange the layout of the site based on different widths. It takes advantage of well structured, semantic HTML markup in order to present a view of the site that is appropriate for each device while still giving all users the full functionality and content of the site.

The most common method of approaching responsive design is “mobile-first,” however, because I had an existing layout that was designed for an 800 pixel wide minimum, I started from my existing layout and then designed around that. There are two possible choices for determining where your design’s breakpoints are: device specific, and content first. In device specific, you set the breakpoints based on the width of the devices that are the most common visitors to your site and the devices that you want to support. The second approach is to let your content dictate the where the breakpoints are by setting a breakpoint at the widths where the content of the site starts to look stretched or out of proportion. The process of finding content specific breakpoints is a largely based on feel and you can have as many as you want. For this site, I chose the following breakpoints:

  • 577 pixels
  • 640 pixels
  • 800 pixels (Original Design)
  • and 1075 pixels

For anything below 577 pixels in width, I am showing the mobile layout as shown on the right. The navigation is collapsed into a drop down list and the sidebar is moved to the bottom of the page. Each photo in the Latest Photos section is also floated left so that they wrap appropriately so that the Latest Photos section expands to the bottom of the page.

At 577 pixels, the only change is that there is now enough real estate to show the standard navigation, so that replaces the drop down list as shown below.

577 Pixels

The next major change comes at 640 pixels in width. At this point, there is enough width to practically move the sidebar back to the right hand column without adversely crunching the Latest Photos section on the bottom. This change is shown below.

640 Pixels

At 800 pixels, I am back to my original layout so the site stops attempting to fill the full screen width and the side gutters appear again. This also leaves a nicely matched Latest Photos section of three rows of four.

800 Pixels

The final breakpoint is at 1075 pixels. At this point, the main container expands again to take advantage of the expanded width for more text horizontally. The Latest Photos section breaks nicely here into two rows of six.

Much to my surprise, the basic process of making the site responsive was relatively simple. At each point, I use a CSS media query like @media only screen and (min-width: 1075px) { } to change the styling of the HTML elements, but there aren’t any changes to the site markup. Clean, semantic HTML5 markup makes the process of making a site responsive significantly easier. The only place where I had a significant challenge in the responsive transition is in handling modal dialogs like when an individual picture is clicked. I’m not entirely happy with where that solution is at this point, but it works. On this site, I intentionally don’t minify my CSS and JavaScript so that you can view my code for your own reference, so please feel free to look at the code and let me know if you have any thoughts or questions.

 
By: Shane
Comments

Comments

Be the first to comment on this post

MSDN Magazine: Develop Hybrid Native and Mobile Web Apps

Friday, March 2, 2012 10:04 AM

MSDN Magazine: Develop Hybrid Native and Mobile Web AppsMy article on building hybrid native and mobile web applications has been published in the March issue of MSDN Magazine.

Mobile applications are all the rage these days. There are currently three major mobile platforms: Apple’s iOS  (iPhone and iPad), Google’s Android , and Microsoft’s Windows Phone , and countless variations within these platforms for the developer to consider. Focusing on any one of these platforms leaves 50% or more of the market unable to use your application, but the cost of building and maintaining the same application on each of the platforms quickly becomes problematic. A web application is another option, but one that leaves the experience diluted and leaves the developer without access to many of the native hardware capabilities. 

In one of my recent projects at EffectiveUI, I spent a lot of time thinking about how to solve this conundrum in a way that provides the best possible user experience while still being cost effective and maintainable. My solution was an application that is a hybrid of a native application and a mobile web application. I had the opportunity to share this solution, and provide a tutorial for building it, in an article for MSDN Magazine , “Develop Hybrid Native and Mobile Web Apps .” I truly believe that this approach is a “best of both worlds” solution that leaves the developer and end user in a better place.

I hope that my approach to this problem helps you in building your applications and I’d love to hear any feedback that anyone might have.

The main text of this post is also cross-posted on the EffectiveUI blog.

 
By: Shane
11 Comments

Comments

  • Ruurd Eijzinga 3/15/20123:48 AM Great article, is there a version for vs2010 ?
  • Shane Church 3/15/20127:48 AM @Ruurd: All of the ASP.NET MVC and Windows Phone 7 code samples in the article are for Visual Studio 2010. The Android project requires Eclipse and the Android SDK and the iOS code requires Apple OS X and XCode.
  • Ruurd 3/15/20128:20 AM sorry, but I get these errors EffectiveUI.MSDN.Web.csproj' cannot be opened. The project type is not supported by this installation. EffectiveUI.MSDN.Phone.csproj' cannot be opened. The project type is not supported by this installation. I am running vs2010 sp1
  • Shane Church 3/15/20128:48 AM You will need the ASP.NET MVC 3 components for the Web project from http://www.asp.net/mvc. You will also need the Windows Phone 7.1 SDK for the Phone project from http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=27570.
  • Kushil Abeyguna 3/25/20123:51 PM Good article. I think many people already have been developing hybrid (HTML5/JavaScript running in a native wrapper) mobile application using open source frameworks such as PhoneGap (which supports six mobile platforms). But I never thought of developing these native shells by myself. This is a good eye opener for most people like me as they would have never thought that their favorite frameworks do a "similar" thing to the above in their native wrappers. Good work indeed. I do not have to stick to a bridging framework like PhoneGap anymore.
  • Shane Church 3/27/20129:18 AM Kushil, (cross-posted from blog.effectiveui.com) Comparing this solution to one like PhoneGap (now Apache Cordova) is a matter of degree. To me, the big difference in the solutions is that Cordova is designed to allow a HTML/JavaScript developer to build a device native application. For that to happen, some of the HTML and JavaScript have to be deployed to the device itself and there remains a dependency on the Cordova JavaScript APIs for native hardware access. On the other hand, the solution I present in the article takes a cross-platform mobile web application and provides it with access to native functionality as needed. The hybrid technique that I describe in the article provides a much finer level of control over the user experience when compared to Cordova and also has the advantage of being accessible on devices that do not have the native application installed. As I stated in the article, none of these approaches are inherently better than the others and you really need to make sure that you keep the business and end user goals in the forefront when choosing a technology stack for a mobile application.
  • ALex 3/29/20121:25 AM Hi Shane, this seems like a very useful approach! Thank you. Having to write just 1 Web Application and still have access to the ressources of the device can save a lot of time. But I am wondering if this approach could also enable the webapplication to be accessible offline? What do you think?
  • Shane Church 3/29/20123:49 PM Alex, Depending on how you architect the site, you could likely make large portions of the site available offline using the HTML5 ApplicationCache interface (http://www.html5rocks.com/en/tutorials/appcache/beginner/). It really depends on how dynamic the data in the site is as to how much you could make available offline. I think it would be extremely challenging to make the entire content of anything other than a completely static site available offline. More likely, you could use the HTML5 ApplicationCache interface to speed loading of portions of your app by caching images and CSS files on the user device. I hope this helps!
  • ALex 3/30/20125:58 AM Thank you very much. I think the approach you are using and the new things that are coming like SPA on mvc 4 (http://channel9.msdn.com/Events/TechDays/Techdays-2012-the-Netherlands/2159) will be very powerful!
  • Mark L 4/16/20129:35 PM Hi Shane, I've just downloaded the sample code from your article, but the Android code doesn't compile as it appears to be missing a referenced library. I get this error: Project 'EffectiveUI.MSDN' is missing required library: 'C:\Users\Shane.Church\Documents\Cartegraph\httpmime-4.1.2.jar' Any chance of posting an updated sample code package that includes this library? Or am I being a numb nuts and it's already there? "
  • Shane Church 4/17/20121:28 PM Mark, The httpmime-4.1.2.jar is part of the Apache HttpComponents project at http://hc.apache.org/index.html. You can download the HttpClient 4.1.3 (GA) release binaries which include httpmime-4.1.3.jar and update the reference in Eclipse.

Angled Table Headers in HTML5 and CSS3

Friday, February 17, 2012 4:09 PM

The original design compI got the design comp above for one of my projects at EffectiveUI and immediately thought, “How am I going to be able to do that in HTML and CSS?'”  The table headers are generated dynamically by system defined sections and could be different for different groups of users, so using an image for the table header was impractical.  I knew CSS3 gave me some new options using 2D transforms, but browser support was uneven.  Another problem in this design that looks like a really minor feature is the carrot under the “QuickNav” text.  Fortunately, the requirements of this project are that we are just supporting the latest versions of IE, Firefox, Chrome, and Safari, so CSS3 2D transforms it is.

My initial attempt didn’t go so well as you can see below.  Not only were the browser implementations of the 2D transforms uneven, but the documentation available online was less than complete as well. 

DxGAngledHeaders1

So all of my headers didn’t line up with their columns and the text was way out of whack too.  It turns out that the browsers calculate the position of an element first, then transform it, so I had to adjust the positioning of the elements to end up where I wanted them.  After some playing with the Skew() and Rotate() CSS3 2D transform methods, I discovered that I needed a little extra markup in each <th> cell to get the display to show up correctly.  Even with that being said, the end markup is still very clean to generate the table:

<div class="quick-nav-container">
    <h4>QuickNav</h4>
    <a class="close" href="#">x</a>
    <div class="quick-nav">
        <table>
            <thead>
                <tr>
                    <th></th>
                    <th class="skew"><div class="odd"><span>All</span></div></th>
                    <th class="skew"><div class=""><span>General</span></div></th>
                    <th class="skew"><div class="odd"><span>Typography</span></div></th>
                    <th class="skew"><div class=""><span>Colors</span></div></th>
                    <th class="skew"><div class="odd"><span>Buttons</span></div></th>
                    <th class="skew"><div class=""><span>Form Elements</span></div></th>
                    <th class="skew"><div class="odd"><span>Windows</span></div></th>
                    <th class="skew"><div class=""><span>Utilities</span></div></th>
                    <th class="skew"><div class="odd"><span>Images</span></div></th>
                    <th class="skew"><div class=""><span>Iconography</span></div></th>
                    <th class="skew"><div class="odd"><span>Layout Grids</span></div></th>
                    <th class="skew"><div class=""><span>Page Templates</span></div></th>
                    <th class="skew"><div class="odd"><span>Media</span></div></th>
                    <th class="skew"><div class=""><span>Misc.</span></div></th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td class="project-name">EffectiveUI DxG</td>
                    <td class="odd"><a href="/Search/SearchByProject?projectName=EffectiveUI%20DxG">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=1&amp;sectionId=1">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=1&amp;sectionId=2">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=1&amp;sectionId=3">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=1&amp;sectionId=4">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=1&amp;sectionId=5">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=1&amp;sectionId=6">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=1&amp;sectionId=7">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=1&amp;sectionId=8">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=1&amp;sectionId=9">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=1&amp;sectionId=10">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=1&amp;sectionId=11">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=1&amp;sectionId=12">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=1&amp;sectionId=13">&#187;</a></td>
                </tr>
                <tr>
                    <td class="project-name">Test Project</td>
                    <td class="odd"><a href="/Search/SearchByProject?projectName=Test%20Project">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=2&amp;sectionId=1">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=2&amp;sectionId=2">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=2&amp;sectionId=3">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=2&amp;sectionId=4">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=2&amp;sectionId=5">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=2&amp;sectionId=6">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=2&amp;sectionId=7">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=2&amp;sectionId=8">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=2&amp;sectionId=9">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=2&amp;sectionId=10">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=2&amp;sectionId=11">&#187;</a></td>
                    <td class="odd"><a href="/Search/QuickNav?projectId=2&amp;sectionId=12">&#187;</a></td>
                    <td class=""><a href="/Search/QuickNav?projectId=2&amp;sectionId=13">&#187;</a></td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

As you can see in the code above, I used no images to achieve this effect.  The X close button in the upper right is a simple anchor tag with the border-radius property set to make it appear to be a circle.  The most interesting pieces to note for the angled headers are the <th class=”skew”> tags and the <div> and <span> tags contained within.  Those div and span tags are the extra markup needed to make all of the 2D transforms play nice with each other to generate the 45 degree angled headers. 

The CSS used to generate the table is as follows:

.quick-nav-container {
    background-color: #666666;
    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
    border-radius: 4px;
    position: absolute;
    z-index: 100;
    padding: 30px 14px 14px 14px;
    display: none;
}

.quick-nav-container h4 {
    position:absolute;
    color: #FFFFFF;
    font-size: 14px;
    font-weight: bold;
    width: 112px;
    top: 0px;
    left: 0px;
    text-align: center;
    padding: 8px;
}

/* creates triangle */
.quick-nav-container h4:after {
    content:"";
    position:absolute;
    bottom:-10px; /* value = - border-top-width - border-bottom-width */
    left:56px; /* controls horizontal position */
    border-width:10px 10px 0; /* vary these values to change the angle of the vertex */
    border-style:solid;
    border-color:#666666 transparent;
    /* reduce the damage in FF3.0 */
    display:block; 
    width:0;
    z-index: 1;
}

.quick-nav-container a.close {
    position: absolute;
    top: 4px;
    right: -12px;
    width: 16px;
    height: 16px;
    text-decoration: none;
    color: #333333;
    background-color: #FFFFFF;
    -moz-border-radius: 8px;
    -webkit-border-radius: 8px;
    border-radius: 8px;
    display: block;
    text-align: center;
    font-weight: bold;
    font-size: 14px;
}

.quick-nav {
    position: relative;
    background-color: #FFFFFF;
    font-size: 10px;
    padding: 20px 90px 20px 20px;
    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
    border-radius: 4px;
}

.quick-nav a {
    color: #333333;
    text-decoration: none;
    font-size: 14px;
}

.quick-nav table th.skew {
    height: 60px;
    width: 40px;
    position: relative;
    vertical-align: bottom;
}

.quick-nav table th.skew > div {
    position: relative;
    top: 0px;
    left: 30px;
    height: 100%;
    transform:skew(-45deg,0deg);
    -ms-transform:skew(-45deg,0deg); /* IE 9 */
    -moz-transform:skew(-45deg,0deg); /* Firefox */
    -webkit-transform:skew(-45deg,0deg); /* Safari and Chrome */
    -o-transform:skew(-45deg,0deg); /* Opera */    
    overflow: hidden;
    border-top: 1px solid #CCCCCC;
    border-left: 1px solid #CCCCCC;
    border-right: 1px solid #CCCCCC;
}

.quick-nav table th.skew span {
    transform:skew(45deg,0deg) rotate(315deg);
    -ms-transform:skew(45deg,0deg) rotate(315deg); /* IE 9 */
    -moz-transform:skew(45deg,0deg) rotate(315deg); /* Firefox */
    -webkit-transform:skew(45deg,0deg) rotate(315deg); /* Safari and Chrome */
    -o-transform:skew(45deg,0deg) rotate(315deg); /* Opera */        
    position: absolute;
    bottom: 15px;
    left: 1px;
    display: inline-block;
    width: 100%;
    text-align: left;
}

.quick-nav table td {
    width: 40px;
    height: 35px;
    text-align: center;
    vertical-align: middle;
    border: 1px solid #CCCCCC;
}

.quick-nav table td a {
    display: block;
    width: 100%;
    text-align: center;
}

.quick-nav table td.project-name {
    width: auto;
    text-align: right;
    font-weight: bold;
    border: none;
    padding-right: 8px;
}

.quick-nav table .odd {
    background-color: #E8E8E8;
}

The most important sections are highlighted above in the selectors for “.quick-nav table th.skew,” “.quick-nav table th.skew > div,” and “.quick-nav table th.skew span.”  This is where the rotation and absolute positioning happens to make the rotation happen correctly.  For the carrot below, “QuickNav,” I used the speech bubbles technique described by Nicolas Gallagher at http://nicolasgallagher.com/pure-css-speech-bubbles/.  The final result is below, pixel for pixel perfect with the design comp and a new technique that I will definitely be keeping in my back pocket for future projects.

The completed angled headers

 
By: Shane
10 Comments

Comments

  • Andy 2/23/20123:23 PM Thanks for sharing this! The lack of support in older browsers may eliminate this from my list of options, but it was nice to be able to have a quick starting point that I could use to show this option to the rest of my team. For anybody reading this that wants to just take the code and play around a bit, make sure you add "border-collapse: collapse" to the table and "padding: 0" to the th elements. I'm thinking Shane must have those defined in another spot in the CSS and that threw me for a loop for a second when I put together a test file. Anyway, thanks again!
  • Shane Church 2/23/20123:54 PM @Andy: Thanks for the comments. Due to the kinds of layouts that we routinely build at EffectiveUI, I typically use Eric Meyer's Reset CSS (http://meyerweb.com/eric/tools/css/reset/) to reset any browser defaults, so that is where the border-collapse:collapse" and "padding:0" elements that you mentioned are defined.
  • Shala 8/24/201212:57 AM Skew is a nonstandard function, e.g. with Firefox 14 it does not work. However there are the standard functions skewX and skewY, if you replace all occurrences of scew with skewX and remove the second argument (which is 0deg always anyways) it works perfectly well.
  • Chrerops 5/7/20174:04 AM Secure Progesterone Hormone Replacement Low Price Mastercard Nevada Brand Propecia Best Buy Discount Clobetasol Saturday Delivery Store Price Baton Rouge Propecia Itch Skin Clonidine Overnight Kamagra Vs Viagra [url=http://byuvaigranonile.com]viagra[/url] Celebrex Online No Prescription
  • Kennlewbrien 6/16/201711:37 AM Comprare Levitra Generico [url=http://buy-levitra-10mg.buylevi.com]Buy Levitra 10mg[/url] Priligy Oder Viagra Propecia Herz [url=http://dapoxetine-online.priliorder.com]Dapoxetine Online[/url] Viagra A Los 40 Anos Foro Cialis 10 [url=http://cial40mg.com/buy-cheap-cialis-on-line.php]Buy Cheap Cialis On Line[/url] Zithromax Dose In Children Cialis Occhi Rossi [url=http://real-viagra-online.via100mg.com]Real Viagra Online[/url] Levitra Food Propecia Atopico [url=http://viacheap.com]viagra[/url] Clomid Jeulin Viagra By Mail [url=http://kamagra-pharmacy.kamagpills.com]Kamagra Pharmacy[/url] Cialis Generic On Line United Pharmacies Propecia [url=http://xenical.ccrpdc.com/buy-generic-xenical.php]Buy Generic Xenical[/url] Ed Meds In Canada
  • Kennlewbrien 6/19/20178:04 PM Buy Bactroban Uk [url=http://lasix.ccrpdc.com/buy-online-lasix.php]Buy Online Lasix[/url] Amoxicillin 500 Viagra Preiswert [url=http://levitra-online.buylevi.com]Levitra Online[/url] Cialis Netpharm Amoxicillin Typical Dose [url=http://cial40mg.com/cheap-cialis-no-rx.php]Cheap Cialis No Rx[/url] Prix De Xenical 120 Mg Canadianmeds 24hr [url=http://buy-online-kamagra.kamagpills.com]Buy Online Kamagra[/url] Mail Order Stendra Internet Cod Only Next Day Delivery Celecoxib 200 Mg Price [url=http://dapoxetine-purchase.priliorder.com]Dapoxetine Purchase[/url] Viagra Online Auf Rechnung Viagra Canadian [url=http://via100mg.com]Buy Viagra[/url] Buy Generic Levitra Uk Compare Viagra To Generic [url=http://viacheap.com]viagra[/url] Tab generic isotretinoin website cod accepted
  • ShanAgow 11/30/20178:31 PM Lexapro Mail Order Us Pharmacy Kamagra Oral Jelly Wiki Cialis With Prescription [url=http://costofcial.com]cialis[/url] For Sale Generic Legally Dutasteride Mastercard Accepted Store Chicago Keflex Online
  • ShanAgow 11/30/20178:31 PM Lexapro Mail Order Us Pharmacy Kamagra Oral Jelly Wiki Cialis With Prescription [url=http://costofcial.com]cialis[/url] For Sale Generic Legally Dutasteride Mastercard Accepted Store Chicago Keflex Online
  • Briguitty 1/28/20185:38 AM Cheapest Indian Prices For Nizagara Cialis O Levitra [url=http://cial20mg.com]cialis price[/url] Generic Levaquin France With Free Shipping With Doctor Consult Levitra Pas Cher
  • ThaBroope 2/1/20187:26 PM Women Viagra Pills Generic Finasteride Drugs Propecia Effetti Collaterali Di Finasteride [url=http://tadalaffbuy.com]cialis[/url] Amoxicillin The Right Dose Forseniors Tadalis Sx Achat En Ligne

Rebuilding s-church.net

Friday, December 16, 2011 4:00 PM

Shane.Church.Web Project StructureAlong with the posts that I’ve been getting back into making recently, I also spent quite a bit of time recently redeveloping the infrastructure of s-church.net.  I rebuilt the site from the ground up using ASP.NET MVC 3, HTML5, CSS 3, and jQuery and I’d like to take some time to describe what I did from a technical standpoint.

The first part of what I did was to create a new ASP.NET MVC 3 project in Visual Studio.  I then analyzed my existing site and and created MVC controllers for each of the main menu items that you see above.  I rebuilt the main _Layout.cshtml master page for the site using HTML5 and the ASP.NET MVC 3 Razor view engine as seen in  Master Layout code snippet below.  I take advantage of the new HTML5 semantic tags like <header>, <nav>, <section>, <article>, and <footer>.  The <header>, <nav>, and <footer> tags are relatively straightforward in their usage, but the <section> and <article> tags are less obvious.  In this site, I use <section> as a container for various pieces of the layout.  Each blog post or photo item container is an <article> in the semantic markup.

 
<div class="page">
        <header>
            <div id="title">
                <h1>@ViewBag.Header</h1>
            </div>
        </header>
        <nav>
            <ul class="ssc_nav">
                <li>@Html.ActionLink("Home", "Index", "Home")</li>
                <li><a href="@Url.Content("~/Resume.pdf")">Resume</a></li>
                <li>@Html.ActionLink("Blog", "Index", "Blog")</li>
                <li>@Html.ActionLink("Photo Album", "Index", "PhotoAlbum")</li>
                <li>
                    <a href="#">Software</a>
                    <div class="ssc_sub_nav">
                        @Html.ActionLink("Windows 7 Gadgets", "Win7Gadgets", "Software")
                        @Html.ActionLink("Windows Mobile Smartphone", "WMSmartphone", "Software")
                        @Html.ActionLink("Windows Mobile Pocket PC", "WMPocketPC", "Software")
                        @Html.ActionLink("Windows", "MSWindows", "Software")
                        @Html.ActionLink("Pocket PC", "MSPocketPC", "Software")
                        @Html.ActionLink("Palm OS", "Palm", "Software")
                    </div>
                </li>
                <li>
                    @Html.ActionLink("Reading List", "Index", "ReadingList")
                </li>
                @if (Request.IsAuthenticated && User.IsInRole("Admin"))
    {
                <li>@Html.ActionLink("Admin", "Index", "Admin")</li>
    }
            </ul>
        </nav>
        <section id="main">
            <div class="main_container">
                @RenderBody()
            </div>
            <div class="side_nav">
                <div class="container">
                    <img src="@Url.Content("~/Content/Images/side_nav_photo.jpg")" alt="Shane Church, Andrea Love, and Ethan Love-Church" class="side_photo" />
                    <h3>Contact</h3>
                    <a href="mailto:shane@s-church.net" class="logo_link">Email Me</a>
                    @RenderSection("SideNav", false)
                </div>
                @RenderSection("SideNavPostContainer", false)
            </div>
            <div class="clear">&nbsp;</div>
        </section>
        <footer>
            <div id="logindisplay">
                @Html.Partial("_LogOnPartial")
            </div>
            Copyright &copy; Shane Church 2011
        </footer>
    </div>

I built the menu hover and drop down behaviors myself using jQuery and some CSS.  The behavior is relatively straightforward and, as I’ve been learning more about HTML, CSS, and JavaScript in my role at EffectiveUI, I found it very easy to implement the menu on my own as shown in the code snippet below.

var menuTimeout = null;

$(document).ready(function () {
    $(".ssc_nav li").mouseenter(function () {
        var $this = $(this);
        $this.find(".ssc_sub_nav").slideDown(200, function () {
            menuTimeout = window.setTimeout(function () {
                $this.find(".ssc_sub_nav").slideUp(200);
            }, 500);
        });
    });

    $(".ssc_sub_nav a").mouseenter(function () {
        window.clearTimeout(menuTimeout);
        menuTimeout = null;
    });

    $(".ssc_sub_nav a").mouseleave(function () {
        window.clearTimeout(menuTimeout);
        menuTimeout = null;
        var $this = $(this);
        menuTimeout = window.setTimeout(function () {
            $this.parent().slideUp(200);
        }, 500);
    });
});

All of the styling of the new site is using CSS 3 with minimal use of images for item backgrounds.  This significantly improves the download size and speed of the individual pages by reducing the number of HTTP requests for images and allowing the browser to do the rendering work.  I’m using Eric Meyer’s Reset CSS to reset all of the CSS settings across all browsers before applying my own styling to achieve consistency between all of the different browsers.  One annoyance to me in the new CSS 3 implementations is the addition of browser specific prefixes like -moz- for Firefox and -webkit- for Chrome and Safari and -ie- for Internet Explorer.  This requires me as the developer to know a lot more about the workings of each browser to achieve consistent results and I end up having the W3Schools reference pages open constantly while developing.  For example, the gradient in the main menu is described by the CSS code below.

ul.ssc_nav {
    height: 34px;
    background: #999999; /* Old browsers */
    background: -moz-linear-gradient(top, #999999 0%, #5B5B5B 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#999999), color-stop(100%,#5B5B5B)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top, #999999 0%,#5B5B5B 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top, #999999 0%,#5B5B5B 100%); /* Opera11.10+ */
    background: -ms-linear-gradient(top, #999999 0%,#5B5B5B 100%); /* IE10+ */
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#999999', endColorstr='#5B5B5B',GradientType=0 ); /* IE6-9 */
    background: linear-gradient(top, #999999 0%,#5B5B5B 100%); /* W3C */
    border-top: 1px solid #000000;
    border-bottom: 1px solid #000000;
    z-index: 200;
}

I wanted to make sure that I maintained all of the existing links which were in the format of /Blog.aspx?id=<id> even though I was switching the site to use a more SEO-friendly URL routing scheme of /Blog/<id>, so I added a route in Global.asax to my LegacyController which then executes a HTTP 301 Permanent Redirect to the new URL so that search engines and people with favorites marked for the old URLs will continue to work correctly.  The routing entry is as follows:

routes.MapRoute(
        "{*allaspx}",
        @"{id}.aspx",
        new { controller = "Legacy", action = "Index" });

and the PermanentRedirectResult MVC action is highlighted below.

public class PermanentRedirectResult: ActionResult
{
    //...

    public override void ExecuteResult(ControllerContext context)
    {
        if (_action == null || _controller == null)
        {
            context.HttpContext.Response.Status = "404 Not Found";
            context.HttpContext.Response.StatusCode = 404;
        }
        else
        {
            context.HttpContext.Response.Status = "301 Moved Permanently";
            context.HttpContext.Response.StatusCode = 301;
            context.HttpContext.Response.AppendHeader("Location", ((Controller)(context.Controller)).Url.Action(_action, _controller, _routeValues));
        }
    }
}

ScreensaverDuring the transition, I also converted my photo album from local file storage to use Amazon’s S3 service.  This change required me to implement a simple controller to use Amazon’s AWS SDK and then I added an ASP.NET MVC controller method in my photo album controller to actually respond with the image from the Amazon service as shown below.  This conversion also required me to retool my custom screensaver that displays images from this site (shown to the left) and my Windows Live Photo Gallery plugin for publishing images to the site to use the Amazon S3 service as well.

 
public ActionResult Image(long id)
{
    MySQLSiteModel model = new MySQLSiteModel();
    var photo = (from p in model.photo
                 join pg in model.page on p.LINK_ID equals pg.ID
                 where p.ID == id
                 select new PhotoViewModel() { ID = p.ID, CategoryID = pg.ID, CategoryName = pg.DISPLAY_NAME, Caption = p.CAPTION, File = p.FILE, UpdatedDate = p.UPDATED_DATE }).FirstOrDefault();

    try
    {
        S3Controller amazonController = new S3Controller();

        Stream data = amazonController.ReadObject("photos", photo.CategoryID.ToLower() + "." + photo.File.Substring(photo.File.LastIndexOf('/') + 1).ToLower());

        return File(data, "image/jpeg");
    }
    catch
    {
        return new HttpStatusCodeResult(404);
    }
}

As you can see illustrated in the snippet above, I have also moved my database connection code to use the Microsoft Entity Framework using the MySQL .NET provider.  The database connections are then handled in code using LINQ-to-Entities, significantly reducing the amount of raw SQL code that I needed.  I did run into some issues with the MySQL provider not supporting some of the standard LINQ operations like .Take() consistently, though I don’t have a good code example for that since I came up with some workarounds.

I also implemented the Metaweblog API in order to facilitate using Windows Live Writer to publish to the blog.  I implemented this using the XML-RPC.Net library as a ASP.NET generic handler.  The interface is shown below.

public interface IMetaWeblog
{
    #region MetaWeblog API

    [XmlRpcMethod("metaWeblog.newPost")]
    string AddPost(string blogid, string username, string password, Post post, bool publish);

    [XmlRpcMethod("metaWeblog.editPost")]
    bool UpdatePost(string postid, string username, string password, Post post, bool publish);

    [XmlRpcMethod("metaWeblog.getPost")]
    Post GetPost(string postid, string username, string password);

    [XmlRpcMethod("metaWeblog.getCategories")]
    CategoryInfo[] GetCategories(string blogid, string username, string password);

    [XmlRpcMethod("metaWeblog.getRecentPosts")]
    Post[] GetRecentPosts(string blogid, string username, string password, int numberOfPosts);

    [XmlRpcMethod("metaWeblog.newMediaObject")]
    MediaObjectInfo NewMediaObject(string blogid, string username, string password,
        MediaObject mediaObject);

    #endregion

    #region Blogger API

    [XmlRpcMethod("blogger.deletePost")]
    [return: XmlRpcReturnValue(Description = "Returns true.")]
    bool DeletePost(string key, string postid, string username, string password, bool publish);

    [XmlRpcMethod("blogger.getUsersBlogs")]
    BlogInfo[] GetUsersBlogs(string key, string username, string password);

    [XmlRpcMethod("blogger.getUserInfo")]
    UserInfo GetUserInfo(string key, string username, string password);

    #endregion
}

One final piece to note is the use of jQuery to make the pages more interactive.  For each major section of the site, I wrote the code as a jQuery Plugin in order to encapsulate the code for each section.  This is a technique that we commonly use at EffectiveUI to make it easier for our clients to maintain the code after a project is complete.  An example from the Photo Album plugin that I wrote is shown below.

//jquery.PhotoAlbum.js
//Copyright © Shane Church 2011

(function ($) {
    var methods = {
        init: function () { },
        loadPage: function (options) {
            var defaults = {
                href: "",
                callback: function () { }
            };

            var opts = $.extend(defaults, options);

            var $this = $(this);

            $.ajax({
                url: opts.href,
                type: "GET",
                dataType: 'html',
                success: function (data) {
                    var $data = $(data);

                    $(".photos_container").empty();
                    $(".photos_container").append($data.find(".photos_container").children());

                    $(".pager").empty();
                    $(".pager").append($data.find(".pager").children());

                    opts.callback();
                },
                error: function (request, status, error) {
                }
            });
        },
        showPhoto: function (options) {
            var defaults = {
                href: "",
                title: "",
                category: "",
                file: "",
                callback: function () { }
            };

            var opts = $.extend(defaults, options);

            var $content = $("#modal-view-photo");
            $content.find(".image img").attr("src", opts.file).attr("alt", opts.category + " - " + opts.title);
            $content.find("h4").text(opts.title);
            $content.find("h5").text(opts.category);
            $content.find("a.close").unbind("click").click(function () {
                $().HideModal({ strId: "#modal-view-photo" });
                return false;
            });

            var options = {
                strId: "#modal-view-photo"
            };

            $().ShowModal(options);
        }
    };

    $.fn.PhotoAlbum = function (method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.PhotoAlbum');
        }
    };

})(jQuery);

As you can see, this was a pretty major rearchitecture of the entire site, but it gave me the opportunity to put a lot of the new techniques that I’ve learned over the last year into practice as well as build an updated portfolio site.  I hope this detailed tour of the site proves useful.  Feel free to comment or contact me directly with any comments or questions!

 
By: Shane
Comments

Comments

Be the first to comment on this post

Dubuque

Friday, October 14, 2011 9:56 AM

CartegraphLogoI spent this past Monday through Thursday in Dubuque teaching HTML, CSS, JavaScript, and jQuery to our clients at Cartegraph.  It was a good trip and the class went really well.  I think they learned a lot and it was a really good group to work with.  I did a combination of lecture style training and interactive workshops where I gave the class a series of tasks for them to complete.  The slides I presented are shared below:

 
By: Shane
Comments

Comments

Be the first to comment on this post