Episode 150 of The SitePoint Podcast is now available! This week the panel is made up of Louis Simoneau (@rssaddict), Kevin Dees (@kevindees), Stephan Segraves (@ssegraves) and Patrick O’Keefe (@ifroggy).
Play this episode directly in your browser — just click the orange “play” button below:
You can download this episode as a standalone MP3 file. Here’s the link:
The SitePoint Podcast is on iTunes! Add the SitePoint Podcast to your iTunes player. Or, if you don’t use iTunes, you can subscribe to the feed directly.
Here are the main topics covered in this episode:
Browse the full list of links referenced in the show at http://delicious.com/sitepointpodcast/150.
Transcript to follow.
Theme music by Mike Mella.
Thanks for listening! Feel free to let us know how we’re doing, or to continue the discussion, using the comments field below.
You might already know of responsive design, mobile-first approach, and graceful degradation techniques to build widely accessible websites and web apps. In this post, I focus on the mobile-first aspect of design, and beyond this will highlight some techniques that could also enhance the desktop version of your site.
iOS5 provides an API for securing authorisation details centrally and providing access to them to any application that wants it. This means that users only have one place to go if they wish to de-authorise or modify account details. Neat.
Rockstar Games released a port of Grand Theft Auto III for iOS and select Android devices in celebration of the game’s 10th anniversary. So, does the epic Liberty City saga of violence and revenge translate to mobile devices?
Software testing now enjoys a level of acceptance that was not always there. In the early days of software development, debugging was the primary form of software test. It was primarily performed by the programmer who wrote the code and the object was to get the application to working without crashing the system.
Mobile sites are becoming extremely popular with businesses today. You could even argue that it’s catching up to Social Media’s popularity. This tutorial is going to show how to make sure your new jQuery Mobile site is performing properly, and getting the results you want.
Your site’s menu system should reflect the style of your site. You can choose smaller, subtler sizes and fonts, or you can scale up to big spaces and matching typefaces. In this tutorial, we are going to create a more subtle, more sophisticated look.
It’s a tricky task to design an image-based background that stretches and shrinks to accommodate different browser sizes. But with a little CSS know-how, you can create a sharp, scalable background that fits both small and large pages without compromising your design.
For those graphic designers taking advantage of jQuery to enhance their sites, this collection of plugins is dedicated specifically to typography enhancing tools.
You don’t need plugins or heavy image files to create a dynamic, intuitive menu, and Rupesh has updated this great tutorial to include added support for Internet Explorer transforms. Make sure you read it to keep up to date with vendor prefixes!
We have an old, classic design buried in the back of our hard drive or hidden in some cobweb-ridden corner of the web. Share yours, and take a look at how far we’ve all come from our first website.
We recently created a CSS3-Only tab control which used the powerful :target selector. One of the major benefits of CSS is that we can restyle HTML how we like; so we’re going to transform our mark-up into a vertical accordion.
The solution works in IE9, Chrome, Firefox, Safari and Opera and doesn’t require JavaScript or images. It fails miserably in IE6, 7 and 8 so you could either use the selectivizr shim or hide the widget from those users and tell them to upgrade.
Our HTML5 code is identical to that used by the tab control. I’ve only changed the
article class to “accordion” and renamed some of the
IDs so it’s easier to understand what’s going on. There are also
five sections since it looks a little better:
Title One
This content appears on page 1.
Title Two
This content appears on page 2.
Title Three
This content appears on page 3.
Title Four
This content appears on page 4.
Title Five
This content appears on page 5.
As before, the clickable section heading is contained
within each
section as the initial h2
tag.
First, we’ll style the article container and
section elements. Each section starts in its closed
state with a height of 2em (note that overflow is set to
hidden):
article.accordion
{
display: block;
width: 30em;
padding: 0.5em 0.5em 1px 0.5em;
margin: 0 auto;
background-color: #666;
border-radius: 5px;
box-shadow: 0 3px 3px rgba(0,0,0,0.3);
}
article.accordion section
{
display: block;
width: 28em;
height: 2em;
padding: 0 1em;
margin: 0 0 0.5em 0;
color: #333;
background-color: #333;
overflow: hidden;
border-radius: 3px;
}
The section title is now styled to use all the available room in the closed state:
article.accordion section h2
{
font-size: 1em;
font-weight: bold;
width: 100%;
line-height: 2em;
padding: 0;
margin: 0;
color: #ddd;
}
article.accordion section h2 a
{
display: block;
width: 100%;
line-height: 2em;
text-decoration: none;
color: inherit;
outline: 0 none;
}
We can now ‘open’ the active section using the :target selector. We set a larger height and background color, then enlarge and re-color the title too:
article.accordion section:target
{
height: 15em;
background-color: #fff;
}
article.accordion section:target h2
{
font-size: 1.6em;
color: #333;
}
If necessary, you can set the section height to
auto so it uses the minimum space it requires.
However, that makes it impossible to add nice CSS3 transitions
which smoothly resizes the element…
article.accordion section,
article.accordion section h2
{
-webkit-transition: all 1s ease;
-moz-transition: all 1s ease;
-ms-transition: all 1s ease;
-o-transition: all 1s ease;
transition: all 1s ease;
}
If anything, this CSS is simpler than the tab control and looks better. But vertical accordions are easy — horizontal ones are far cooler! Stay tuned to SitePoint for more :target code soon…
Very recently, at Fraudpointer.com, having reached a database of 25Gb after just six months of operation, we decided to start using replication for our backend persistent storage.
Replication of MySQL can be a solution to various problems that you might want to solve:
MySQL documentation on replication, that can be found here, is quite explanatory and gives more detail about these uses.
Before implementing replication, we had a configuration such as the following:
We had a debian squeeze machine (name: Plato) with MySQL 5.1. installed and serving all of Fraudpointer traffic. When we decided to implement replication it was already 25Gb. A lot of transactions took place per minute, and we were facing two major problems.
1) We wanted to take daily backups and backup put a lot of load on the machine. Though the backup utility that we used (Percona xtrabackup) didn’t lock the database, the machine was getting quite unresponsive during backup time.
2) We wanted to run heavy queries and get reports, very frequently. Just this was a good reason to start discussing replication.
After MySQL replication, we are now in the following picture:
We now have two machines with MySQL installed. The old one, Plato, is now acting as the Master and the new one, Ares, is now acting as the Slave of the replication scheme. In our setup, the advantages of this configuration are as follows:
1) We can get the daily backups from the Slave. No load on the production Master machine for this task.
2) We can get our reports from the Slave node.
3) If the Slave node is down, this is not a problem at all. Replication is performed asynchronously and when the Slave node is up and live after a downtime, it continues replication from the point it has been paused.
4) Records that are created or updated at Master machine, are almost instantly “transferred” to Slave machine (even if asynchronously).
Here is the process that we followed to carry out the replication:
In the first phase of the work, the overview of what we did is as follows:
1) On Master
2) On Slave
1) Allow remote connections
Since you are about to change the bind address on your MySQL server, you are essentially allowing access to your MySQL server from “remote” machines. If you do not do that, after the change of the bind address and restarting of your MySQL server, users from remote or local machines will not be able to connect to your server. All the remote and local machine IPs need to be granted access for the users that access MySQL from these machines.
The following mysql commands (which can be issued using mysql shell)
mysql> grant all on *.* to bar@’10.100.10.55’ identified by ‘bar_password’; mysql> flush privileges;
allow the user ‘bar’ to connect to this MySQL server and to all databases from the machine with IP ’10.100.10.55’. This is necessary even if the user connects from the machine that MySQL server is installed.
Hence, connect to your MySQL server using mysql and set these commands accordingly before proceeding to the following. Don’t forget that this is true for the ‘root’ user too, even if he connects from the local machine.
2) Set bind-address to the IP of the machine.
This is done inside the my.cnf file.
bind-address is a configuration parameter of the
section [mysqld]. Set it to the IP of your Master
machine. In our case, it was 10.100.10.80. Note that if you have
enabled skip-networking you need to disable it.
3) Set binary log file pattern
The parameter is called log_bin and it should exist
in the [mysqld] section. Note that the full path to
the binary log file should be given. Example:
/var/log/mysql/mysql-bin.log.
Important gotcha: make sure that the folder/disk has enough space to write the binary logs there.
4) Set server id
This is the Master replication server ID. It has to be unique among all the ids used in the whole replication setup. For example, set this to “100” and make sure that you set “101” on your Slave (see later).
The parameter is server-id and should be set in the
section [mysqld].
5) innodb_flush_log_at_trx_commit and
sync_binlog
These should be set to “1”, both of them. According to MySQL documentation for the greatest possible durability and consistency in a replication setup using InnoDB with transactions … you have to do this. More on this you can find here.
These parameters are set in section [mysqld].
6) RESTART MySQL Server
Having done all the necessary changes on the configuration file of MySQL Server and having granted access to all existing users to be able to connect using their IP, you can restart your MySQL Server.
7) Create user for replication
You need to create a user that will have the right to work as the replication/slave client. The following commands:
mysql> create user ‘repl’@’10.100.10.103’ identified by ‘slavepassword’; mysql> grant all on *.* to ‘repl’@’10.100.10.103’; mysql> flush privileges;
are creating the user ‘repl’ and give him the right to do replication from the slave machine with IP 10.100.10.103 using the specified password.
1) Install MySQL Server
On Slave machine you need to install MySQL Server.
2) Stop MySQL server
You do not need to have it running, for the time being. Proceed with changing MySQL configuration parameters to support Slave replication.
3) bind-address
Set bind-address to the value of the IP of your
Slave machine. In our case was 10.100.100.103. The parameter
should be set in the [mysqld] section.
4) log_bin
Set the full path to the binary log file. For example:
/var/mysql/log/mysql-bin.log. The parameter is set
in the [mysqld] section of the my.cnf
file.
Important gotcha:: make sure that your binary log folder has lots of space. You will need it.
5) server-id
You need to give the server ID for the Slave node for this replication setup. Put for example “101”. It has to be different from the server IDs of the Master and other Slave nodes in your configuration.
Do not start Slave MySQL server. You still do not need to do that.
You are done for now. Phase 1 is finished.
In Phase 2, we will start replication.
I know. I’m the author of a motivating book on successful freelancing (The Principles of Successful Freelancing, SitePoint), so why would I write a title like that?
The truth is I sucked at being a freelancer the first time. To be honest, I wasn’t much better the second time either. The reason? I didn’t have enough business experience under my belt.
Cast your mind back to the mid-nineties (no, we didn’t wear flares!). I had been working in a totally unrelated industry when I started to design and build websites in my spare time (yes, the days of table-based layouts and Perl programming).
I was great at what I did: I had a design degree, clients loved me, I was a quick learner with HTML and it didn’t take me long to learn how to manage a Linux server with Apache.
Before you knew it, I had enough work on the horizon to ditch my full time employment and start creating websites full time. It was great: flexible hours, interesting projects, working in the comfort of my own home and I felt like I was finally doing what I really loved.
The issue was, I wasn’t doing what I didn’t enjoy. You know: finances, invoicing, contracts, legal and administration. I lasted many months before I admitted to myself that I wasn’t charging enough, I was sending out invoices way too late, and I wasn’t aggressive in chasing them. My cash flow was all over the place, and I had trouble making ends meet.
It was obvious to me that when I started freelancing, I focused on what I was good at, and what I enjoyed doing, to the detriment of my finances and my business.
It didn’t take long for me to start applying for jobs within other companies once I had come to this realization. Sure, I didn’t get to work from home any more, but I was still doing what I enjoyed, and even more importantly, I was learning about everything else while I went, with someone else paying me to do it.
It wasn’t until I had worked in a senior role at a few other companies that I felt confident I had enough skills in enough areas–mostly areas I didn’t know much about the first time–to succeed as a freelancer.
If you are finishing college and thinking of becoming a freelancer full time, my advice is don’t. Sure, take on the occasional weekend project (with your employer’s permission, of course), but land yourself a job that will help you skill up in the areas you aren’t as good at.
Embrace that opportunity and learn everything about as many other roles in your employer’s company as you possibly can. Offer to go on sales calls, help scope new projects, even do the filing between other more exciting tasks.
Before too long, invoicing, sales, chasing debtors and balancing the books won’t be as daunting, and dare I say it, nor as boring as you once thought. Once you have a more rounded skill set, and probably a greater desire than ever to freelance, you can be be confident in stepping out there and doing it.
Best of luck making that well informed leap!
Less code duplication, more code reuse is a goal of OOP, but sometimes it can be difficult with PHP’s single inheritance model. Traits offer a workaround to horizontally reuse code across different class hierarchies. They’re new in PHP 5.4 so learn about them today!
A problem that has plagued web developers for years is how to add real-time information to their applications, such as a progress bar for file uploads. Learn how a new feature in PHP 5.4 can be used to create a dynamic upload progress bar without any external libraries or browser dependencies.
Modern geolocation applications use latitude and longitude to identify the location of people and places to within a few meters – but it’s highly unlikely you’ll answer the question “Where on Earth are you?”. Learn how to use the Yahoo! Placemaker server and write a simple program to ask users where they are before identifying their location in concrete terms.
Including a slew of extra files at the top of your scripts can be a drag! Learn about the “history of autoloading” and the current PSR-0 standard used in many PHP frameworks such as Lithium, Symfony, and Zend, that makes lengthy include lists a thing of the past.
This is Part 2 of the 3-part series that shows you some of the inner-workings of the Yii Framework’s component architecture. In this installment you’ll learn how you can do event-based programming in PHP and how Yii’s CComponent class helps facilitate it.
Vendor prefixes enable web developers to experiment with new standards before they reach the Candidate Recommendation stage. I previously wrote how these prefixes are also a mechanism browser vendors use for handling timing conflicts between implementations and specifications. In building demos of new features for our IE Test Drive site and in various presentations, many of us on the IE team deal extensively with vendor prefixes.
This article describes a pattern our team has used to make things significantly easier when developing with vendor prefixes. We’d like to share it with you and hear your thoughts on this approach or any others you consider a best practice.
When using script to access CSS properties with vendor prefixes, it’s easy to end up with code that looks like this:
var elm = document.getElementById("myElement");
elm.style.msTransitionProperty = "all";
elm.style.msTransitionDuration = "3s";
elm.style.msTransitionDelay = "0s";
elm.style.webkitTransitionProperty = "all";
elm.style.webkitTransitionDuration = "3s";
elm.style.webkitTransitionDelay = "0s";
elm.style.MozTransitionProperty = "all";
elm.style.MozTransitionDuration = "3s";
elm.style.MozTransitionDelay = "0s";
elm.style.OTransitionProperty = "all";
elm.style.OTransitionDuration = "3s";
elm.style.OTransitionDelay = "0s";
While functional, it’s bloated, ugly, and error-prone.
A better pattern is to define a method that loops through a list of property names and returns the first supported property or null if the browser doesn’t support any of them.
function FirstSupportedPropertyName(prefixedPropertyNames) {
var tempDiv = document.createElement("div");
for (var i = 0; i < prefixedPropertyNames.length; ++i) {
if (typeof tempDiv.style[prefixedPropertyNames[i]] != 'undefined')
return prefixedPropertyNames[i];
}
return null;
}
We then initialize a variable for each vendor-prefixed property we use, passing it an array of possible properties in the order we prefer to use them.
var transformName = FirstSupportedPropertyName(["transform", "msTransform", "MozTransform", "WebkitTransform", "OTransform"]); var backfaceVisibilityName = FirstSupportedPropertyName(["backfaceVisibility", "msBackfaceVisibility", "MozBackfaceVisibility", "WebkitBackfaceVisibility", "OBackfaceVisibility"]); var transitionName = FirstSupportedPropertyName(["transition", "msTransition", "MozTransition", "WebkitTransition", "OTransition"]); var animationName = FirstSupportedPropertyName(["animation", "msAnimation", "MozAnimation", "WebkitAnimation", "OAnimation"]); var gridName = FirstSupportedPropertyName(["gridRow", "msGridRow", "MozGridRow", "WebkitGridRow", "OGridRow"]); var regionsName = FirstSupportedPropertyName(["flowFrom", "msFlowFrom", "MozFlowFrom", "WebkitFlowFrom", "OFlowFrom"]); var hyphensName = FirstSupportedPropertyName(["hyphens", "msHyphens", "MozHyphens", "WebkitHyphens", "OHyphens"]); var columnName = FirstSupportedPropertyName(["columnCount", "msColumnCount", "MozColumnCount", "WebkitColumnCount", "OColumnCount"]);
Then code throughout your site that uses these properties becomes something like this:
var elm = document.getElementById("myElement");
if (transitionName) {
elm.style[transitionName + "Property"] = "all";
elm.style[transitionName + "Duration"] = "3s";
elm.style[transitionName + "Delay"] = "0s";
}
else {
// fallback for browsers without CSS3 transitions
}
Note the simple feature detection enabled by returning
null in FirstSupportedPropertyName.
That pattern also works when CSS properties have vendor prefixes. You can use a slightly different pattern for cases where a CSS value (for example, linear-gradient) has vendor prefixes:
function FirstSupportedFunctionName(property, prefixedFunctionNames, argString) {
var tempDiv = document.createElement("div");
for (var i = 0; i < prefixedFunctionNames.length; ++i) {
tempDiv.style[property] = prefixedFunctionNames[i] + argString;
if (tempDiv.style[property] != "")
return prefixedFunctionNames[i];
}
return null;
}
var linearGradientName = FirstSupportedFunctionName("backgroundImage", ["-ms-linear-gradient", "-moz-linear-gradient", "-webkit-linear-gradient", "-o-linear-gradient"], "(top, black, white)");
var radialGradientName = FirstSupportedFunctionName("backgroundImage", ["-ms-radial-gradient", "-moz-radial-gradient", "-webkit-radial-gradient", "-o-radial-gradient"], "(50% 50%, circle cover, black, white)");
A common question is what property names to use if some browsers don’t yet support the property or if no browser supports the standards-based property without a prefix. There are a couple approaches, each with merit:
You need to determine the right path for your site. In most of our demos we want to show off new web platform functionality in any browser that supports it. And since small errors in these demos don’t create big problems for users, we usually choose option #1. On the other hand, if you have a production site where a change in behavior will cause a problem for your business, you may opt for the more risk-averse path.
Regardless of which path you choose, the one constant is testing. When using vendor-prefixed properties you’re leveraging early, often unstable functionality that can change even after a browser first introduces support for a property, so it’s critical to test with each browser update to make sure your site functions as expected.
Widgets are small pieces of content that can be placed in one of the widgetized regions of your WordPress theme. A widget may contain some simple static content like a newsletter subscription form, introductory text, advertisements or some dynamic content such as a list of recent tweets from your Twitter account.
In this article you will learn:
Static widgets can be used to place some unchanging text or HTML code in a region. These are very easy to create and they will be sufficient for most content you will need to add to your blog’s sidebars.
In this example we will create a widget that will show a subscription form to an email newsletter in the sidebar of the blog. Follow the steps below having logged into the WordPress administration panel.
Drag and drop the Text widget to a region in the sidebar as shown
in the image below:
Expand the menu and paste the needed text or HTML code:
Click on the Save button. The widget with its
content will appear in the front end of the website in the
sidebar as shown in the image below:
In this tutorial we will create a widget for showing a Twitter
feed in the sidebar. I will illustrate this example by creating a
plugin that adds a new Widget called “Twitter Feed” to the
Widgets interface. To accomplish the same with the theme, place
the entire code in the functions.php file of your
WordPress theme.
Before starting the definition of the Widget we must first create the plugin that will contain the definition.
Create a file named tweet_feed.php in the
wp-content/plugins/ directory under your WordPress
installation directory.
Open a PHP code section and then place the comment section. WordPress looks for the above comments in the first few line of a PHP file to identify it as a wordpress plugin file. The information in this comment section will be used to show the plugin in the plugins administration page.
Step 3: Create A Sub Class Of WP_Widget
Create a sub class of the predefined class
WP_Widgetwith a descriptive name. I will useTwitter_Feed_Widgetin this case. The sub class should have four methods:
widget()update()form()Twitter_Feed_Widget()(or whatever the name of your widget class is)Even if your server is running PHP5 it is necessary to define a function with the same name as the class name.
class Twitter_Feed_Widget extends WP_Widget { function widget($args,$instance) { } function Twitter_Feed_Widget() { } function update($new_instance,$old_instance) { } function form($instance) { } }This forms the framework in which the entire definition of the widget will be placed. In the above set of functions only the
Twitter_Feed_Widget()andwidget()functions are mandatory.The Widget Options Panel is Optional
Defining the
form()andupdate()functions is optional. They are necessary only if your widget needs some configuration input from the user. You can leave them out if you don’t want to provide any widget options. In that case the options panel will shown as given in the image below.Step 4: Define the Options Panel Interface
WordPress expects the
form()function defined above to output the input fields to the receive input from the user. In the case of the Twitter Feed widget we will provide the following options:
- Title of the Widget
- Username of Twitter user
- Number of tweets to show.
Below is the definition of the
form()function for the Twitter feed widget:function form($config) { ?>The
form()Function Explained
- The function takes one argument –
$config. This variable contains the configuration values for this widget.- The fields in the options are placed within a
tag that is submitted via an AJAX request. Which means a form tag shouldn’t be added in the definition above. WordPress handles the saving of the widget data for you.- The
$this->get_field_name()and$this->get_field_id()functions are used to generate names for the form fields so that there are no conflicts in names with the input fields on the Widget options page.Step 5: Save Options Panel Settings
The business logic that saves the settings selected in the options panel above should be placed in the
save()function. In the case of our Twitter feed:function update($newinstance,$oldinstance) { $instance = $oldinstance; //update the username $instance['username']= $newinstance['username']; $instance['title'] = $newinstance['title']; $num = (int)$newinstance['num']; $num = intval($num); $num = ($num>1)?$num:1; $instance['url'] = "http://api.twitter.com/1/statuses/user_timeline.json?screen_name={$newinstance['username']}&count={$num}"; $instance['num'] = $num; return $instance; }The
update()Function Explained
$newinstances in this case – has the configuration information of the widget as it was entered in the options panel. WordPress automatically detects all the form elements and uses their names for array elements.$oldinstance in this case – has the configuration information of the Widget prior to changing the settings.Options Panel Doesn’t Support File Uploads
You cannot add a file field in the options panel of a widget. If your configurable widget takes file inputs from the user then you must create a separate administration screen for the widget’s options and add a URL field in the widget configuration form.
Now we are going to define the widget itself. WordPress expects the HTML of the widget to be generated by a function named widget(). Shown below is the definition of the Twitter Widget:
function widget($args,$instance)
{
extract($args,EXTR_SKIP);
if (empty($instance['url']) || empty($instance['username']))
return;
$title = ($instance['title'])?$instance['title']:"Latest Tweets";
$tweets = $this->get_tweets($instance['url'],$instance['username'],$instance['num']);
$max = $instance['num'];
echo $before_widget;
?>
As a business entity, there’s really no difference, legally-speaking, whether you consider yourself a freelancer or business owner. Yet, the distinction is an important one to make, not only to determine who your target client will be, but also to establish your future goals, write a business plan, and so forth.
The term freelance comes from medieval mercenary warriors, called “free-lance” because their lance was not sworn to any lord’s services, but was available for hire. The freelancing lifestyle offers more freedom than “being in business”—especially for a single person. I know someone who pulled up stakes and traveled throughout Europe while still maintaining his freelance clients. On a recent discussion on LinkedIn, someone made this poetic observation:
We’re freelancers. Each contract is a mission; each mission is an adventure (a bit heroic, isn’t it?).
As a freelancer, you’ll be contracting yourself out to perform a certain task. You might work for a company as an independent contractor to build a website, do some programming or SEO. You might also work with other design firms or for a company with an in-house web team that you’d interface with. You probably don’t have plans beyond being a one-man or one-woman show and supporting yourself by trading your time for dollars.
I look at the business model as being a consultant paid to produce a certain result. It involves being able to understand and solve a client’s bottom line business issues, using your expertise in web technology and Internet marketing. The typical client would be businesses, corporations, and non-profits who have no in-house web resources available to them. The ultimate goal would be to eventually hire freelancers or employees to replace yourself, so you can work on your business rather than in it.
Having a portfolio is always a concern when first stating out. It’s a Catch-22: you can’t get clients without a portfolio, and you can’t build a portfolio if you don’t have any clients. Pursuing the business model, I found that none of my early clients even asked to see mine. If you are freelancing, then a portfolio may be more essential, especially if you are looking to sub-contract to other agencies. No matter which path you take, you’ll have to figure out how to find and be found by your clients (marketing) and how to reach an agreement to do business with those clients (selling). Learning how to market and sell your services is crucial, regardless of if you are pursing the “business” concept or that of a freelancer.
For me, freelancing felt too much like working for someone else—like a subordinate paid to push the right buttons on the keyboard, instead of someone providing a business solution. That’s why I never bothered with freelance marketplaces where you’re one of a hundred other low-ball bidders. I preferred to be paid for my knowledge and expertise, and be viewed as a peer. But that’s me. There isn’t a right or wrong choice. You ought to pursue whichever fits you best.
Which do you prefer? Do you market yourself as a freelancer or a business, and was that a deliberate choice? Post your comments.
Image creditIf you haven’t yet downloaded the free sample chapter of Earle Castledine and Craig Sharkie’s latest magnum opus for SitePoint, jQuery: Novice to Ninja, 2nd edition – New Kicks and Tricks, it’s high time you did. Or just cut straight to the chase and buy the book!
Why? Well, as someone who bought the first edition, I can vouch that there is plenty of new material in this edition, and the sample chapter is an excellent example.
Tell you what: let’s just take a look at it now. Here we go.
No exploration of advanced jQuery and jQuery plugins could be complete without a hat-tip to the newest kid on the block, jQuery Mobile.
Mobile moves jQuery away from the desktop and onto, well, “mobile” devices. Better yet, it builds on the lessons learned by both Core and UI, so even if you have only a passing understanding of those projects you’ll be ready to roll with Mobile. In fact one of the toughest things to come to terms with when you’re developing with Mobile is the extra steps it’ll take to view your handiwork in the target platforms.
No more ALT+TAB and refresh for
Mobile developers—it’s now CTRL+S, pick up your
phone or tablet PC, and hit reload.
jQuery Mobile blends the cross-browser and cross-platform support we know and love from jQuery with the power, flexibility, and design we turn to UI for—it’s a plugin, but not only does it extend jQuery, it extends the places where you can rely on jQuery. You can select, bind, animate, and chain as you’d expect from a plugin, but you can also tap and swipe, use more CSS3 than ever before, and, most importantly, use your mastery of jQuery to make that next must-have application.
You’re able to focus on your application’s goal and let Mobile help you out without getting in the way—include two files, à la jQuery UI, and you’re away!
...
Looks familiar! Like you’re accustomed to, you can use jQuery’s own CDN to deliver your files as we’ve done here, or you can grab the files yourself and include them locally.
Using jQuery’s CDN, your minified and zipped files come in at 7kB and 24kB respectively—easily small enough to be useful on a mobile network. And you’ve got a host of platform options to access those mobile networks with. As it says on the jQuery Mobile website, “Mobile has broad support for the vast majority of all modern desktop, smartphone, tablet, and e-reader platforms.”
And this is no small claim: jQuery Mobile’s graded browser support matrix sees it catering to an impressive two dozen target platforms. This is not bad if you consider that some of the competitor products officially support only one.
There are too many platforms for us to duplicate the full list of the graded support matrix, but you can find them all on the jQuery Mobile site.
Instead, let’s take a look at the coverage levels you can expect for each grade:
Mobile’s documentation is nearly as comprehensive as the support is. Each method and property is covered, and the documentation itself is written using Mobile —clever, huh? Arguably the documentation is easier to navigate on a smartphone than it is on the desktop!
As plugins go, jQuery Mobile is even more rich than jQuery UI—it has more features baked in, and more functionality that works as soon as you add the files to your application. And as Mobile is grounded in the HTML5 and CSS3 that are driving desktop development, it can even be enticing to non-mobile use cases.
Its support is still growing, and there are possibly some features that we’ll see added in later releases.
While Mobile doesn’t yet rate a mention in the navigation of jQuery Core or UI sites, there are myriad features to make applications that belie just how new the library is. Let’s take a look at some of those features.
By now we know our client nearly as well as we know jQuery and jQuery UI, so it’s a safe bet for us that a mobile application with a social aspect is on the cards.
Let’s up the ante and deal with their next request by creating a mobile-based card game.
We’ll implement jQuery Mobile by making Pop Trumps: The Jemimas, the world’s first card game that combines the thrill of trumping your friends with the face of the newest rock star to hit the charts, as seen in Figure 4.1, Figure 4.2, and Figure 4.3.
Figure 4.1.
The face of Pop Trumps
Figure 4.2. Our Pop Trumps home page
Figure
4.3. The winner’s screen
Rather than go through every line of code, let’s focus on the Mobile-specific code where we can:
⋮
We have already looked at the Mobile requirement includes, but
they are worth mentioning again. Unlike other jQuery projects,
and in order to achieve the wide range of platform support, a
great deal of manipulation occurs well before the
document.ready event fires. As a result, we need to
add our includes in the head of our document to achieve the best
user experience.
While we’re in the document head, let’s look at that new
meta element:
jQuery Mobile draws heavily on HTML5, and here we have an HTML5 element that normalizes the cross-platform display of our application. It tells our browser that our content should be as wide as it can be and that it should be at a 1:1 scale. This is important, given the wide range of resolutions our application may encounter.
That last content value—user-scalable=0—tells our
browser not to make our content zoom. If zooming is something
you’d like in your app, just omit that value and go with the
browser’s default behavior.
Speaking of HTML5, let’s take a look now at our document structure. Again, if you have already worked with HTML5, there should be few surprises for you—except possibly how well Mobile embraces the language.
⋮ ⋮
⋮ ⋮ ⋮
At its heart, our page is a group of section
elements with a data-role attribute of page. You
could also use div elements instead of
sections—here, the attribute is more important than
the element, as the data-role tells Mobile each of
the sections will be a page in our application. We
further delineate our pages with unique id
attributes that serve as anchor targets for our navigation. Where
a desktop might use ids to jump or scroll to content, Mobile uses
them to transition between pageviews.
Inside our second section we’ve shown our basic
pageview layout—a header, div, and
footer, again all with data-role
attributes that help Mobile apply its under-the-hood changes.
Inside these elements we just add whatever HTML we need and
apply data-role attributes where it suits. Let’s try
some now:
START
Our first section with the id of
home has an anchor which we tell Mobile we’d like to
display as a button in our UI—we simply provide the
data-role of button, and Mobile does
the heavy lifting for us. Using the hash reference in our anchor
is all we need do to load our next section, with an
id of albums, into view.
In our albums section we continue using the simple
HTML5 data attribute-driven approach. We tell our
header to apply a theme using, you guessed it,
data-theme.
We do the same for our unordered list, as well as telling it to
be a data-listview, and the anchors in the list to
have a data-transition of flip to
control how our pages “turn”:
Select an album by The Jemimas to play
Tapping the anchors in our attractively styled
listview will now cause the
album-designated page to “flip” into to view, which
adds nicely to our card-like effect. You can also use
slide, slideup, slidedown,
pop, and fade; if you’re a fan of
jQTouch,you
might notice that these transitions have been ported from that
library with only minor changes. After our flip
we’ll have dealt one of our cards, and the players can get into
some serious trumping. For us, though, the real interest lies in
three new data-roles and a seamless DOM
manipulation:
The first new data-role is a
fieldcontain, which does what you’d expect: contains
fields. If you like, this data-role can be applied
to a fieldset for some extra semantic sugar. The
next is the slider role inside our
fieldcontain, and the last is a
controlgroup, which draws its name from an HTML5
hgroup and is used to group buttons.
The DOM manipulation triggered from a slider
data-role shows Mobile’s roots in jQuery UI—the
select element and its associated label
are hidden in the interface and replaced by a sliding flip-toggle
switch popular in mobile devices and illustrated in Figure 4.4.
Figure 4.4. jQuery
Mobile flip-toggle and grouped buttons
The controlgroup value has a no-less-striking effect
in the interface, which it achieves using CSS alone (no DOM
manipulation). By itself, the controlgroup value
draws the links together and applies rounded corners to the first
and last elements in the group. If you also add
data-type=”horizontal” to the div
containing the controlgroup value, as we’ve done in
the preceding markup, the grouped buttons display in a row as
you’d expect.
And our last data attribute is
data-direction=”reverse”, which works with our
transitions by reversing them. For example, where the default
behavior is for a view to move in from the right of the screen,
our data-direction attribute causes it to go out
toward the right. When controlled, it provides the user with a
strong sense of movement within the application. It doesn’t
simply shift along an apparently endless series of views; rather,
it moves around a series of pages like moving through chapters in
a book:
CONTINUE
And speaking of moving through chapters, we’ve reached the point where we can start talking about writing our jQuery Mobile code. Well, almost.
Before we talk about the code we’ll write, we need to cover one
more piece of code that runs without us doing anything: the
mobileinit event. jQuery Mobile’s default
transformations and styling are so good you’ll have little need
to apply any changes, but for those rare times when they are
required, you can leverage the mobileinit event—it
allows you to extend or configure options as soon as the event
fires.
This means you won’t need to overcome defaults—you can change
settings before they’re applied, and there’s no need to wait for
the DOM to load. So you won’t have to wait for
$(document).ready() to take effect, nor
document.loaded.
As a result, it’s recommended you reference your own local script files after referencing the jQuery library, as normal, and before referencing Mobile, like so:
So we have sorted our semantic HTML, our source files are all in
place, and the mobileinit event has fired. Let’s
take a look at the code we’ve written to bring our game to life …
But that’s where we must leave our excerpt. As well as downloading this free sample chapter, you can also browse the Table of Contents and Index before you decide to buy jQuery: Novice to Ninja, 2nd edition – New Kicks and Tricks by Earle Castledine and Craig Sharkie.
If you want traffic from search engines, you know that you need to optimize your page for your target keywords. But where on the page should you place your keywords?
Imagine your target keywords are seeds: will you throw them in the air and hope they grow wherever they fall, or will you place them precisely where they’ll get the most sunlight (and capture the most attention)?
When you look at the big picture, popular search engines like Google have been so successful because they are able to determine the most relevant websites for the keywords queried, while penalizing sites using spammy tactics. This has led to a more satisfactory search experience for users, and a more challenging experience for web marketers and developers.
For example, the once-meaningful keyword meta tag has been relegated to the “obsolete” corner for its heavy abuse by SEOs hoping to gain an edge by keyword stuffing. The same can be said for description tags and pages bursting at the seams with repeated keywords. The goal of search engines is to deliver the most relevant content to their users, and that should be your goal as well. Rather than trying to trick search engines into ranking your site higher, which often works against your rankings, focus on delivering more appropriate keywords in well-placed areas of your site code. Here are five important areas to focus keywords on:
The title tag, which shows up as the title in search results and on the browser window, is the most important place to place your keywords. There are several ingredients that should go into a well-optimized title tag:
Don’t overlook this fundamental element of each web page. While it helps users make sense of what they will find on the page, it does the same for search engine bots. Use the URL to include keywords from the page, making sure to keep it concise and readable. Users find links with readable, descriptive terms more trustworthy, so there’s no reason not to name your directory files and folders logically with keywords.
NoteUse caution (and the correct redirects) when changing the URLs of existing pages.
SEOs have considered h1 important for years. With
the advent of HTML5 and its new semantics, mass confusion has
ensued about whether search engines will understand the new
structure. Whereas before websites were generally discouraged
from using multiple h1 tags, the new semantic markup
encourages h1 tags at the head of multiple
sections.
As it turns out, search engines won’t be penalizing you for using
multiple h1 tags, and apparently never have. Google
engineer Matt Cutts said in a 2009 video, “Use (the
h1 tag) where it makes sense and more sparingly, but
you can have it multiple times.” That doesn’t mean the tag should
be abused, however—there are still safeguards in place to
penalize sites using spammy tactics, such as using
h1 tags for large amounts of body text. To learn
more about this topic, check out What Potential Impact Can HTML5 Have on SEO?
Of course, it would only make sense that your body text should contain keywords. If your site is legitimate and you’re targeting the right audience, it should be easy to naturally weave keywords into the copy. But how many keywords are needed to affect SEO?
SEOmoz recommends that writers aim for for 2-3 keywords on a typical page, and 4-5 on pages with more copy. If more keywords appear naturally as it is written, it won’t hurt anything, but don’t add more for the sake of SEO; anything above those limits won’t affect rankings much, if at all. In a nutshell, relevance and quality reign supreme over keyword density, so make sure the keywords flow well with the text and don’t sacrifice quality for more keywords.
Images are sometimes the forgotten child of SEO, but they too can bring valuable search traffic—even some traffic that regular text can’t reach. How many times have you searched for an image and ended up on the website that hosts the image? People often search for images alone, so it’s worth your time to optimize yours with keywords.
First, make sure the images are given logical, readable
names—with keywords, if appropriate. For example,
cupcake.jpg is better than
img-00012.jpg. Next, don’t skimp on your
alt tags; they are required for better usability in
case your image can’t be seen, and they tell search engines what
the image is. My advice is to write whatever you would want a
user to know if the image didn’t load, ideally using some
keywords.
Finally, ensure the image is in the right context—this is perhaps the most important feature that search engines look for. In short, place the keyword-optimized image close to keyword-optimized paragraph and header tags, and you’re on your way to turning up in an image search.
Resources:
Hey there, all you JavaScript and jQuery wannabes!
As part of the launch of our latest book “jQuery: Novice to Ninja, 2nd Edition. — New Kicks and Tricks” we’re laying down the challenge for all of you to test your jQuery knowledge. Below, you’ll see a screenshot of the first of nine sets of questions from our jQuery Ninja Test.
Take the
test, and see if you can attain jQuery Ninja
status!