Tuesday, March 31st, 2009
There are a ton of tutorials already out there about creating content sliders with jQuery.
So why bother writing another one? While I don’t think that the existing tutorials are
incorrect, bad, or otherwise unacceptable, I haven’t found one that met my needs.
With my attempt at a content slider, I’m hoping to accomplish the following:
View the Demo
Get the Source Code
Let’s start with the HTML we’ll base our jQuery around. We’ll start with a <div> to hold
the content slider, which we’ll give a class attribute of “contentslider”. Inside that, we need
two more <div> elements with class “cs_wrapper” and
“cs_slider”—these will hold all of the entries and allow for the content to move
left and right.
<div id="contentslider"> <div class="cs_wrapper"> <div class="cs_slider"> <!-- Content goes here --> </div><!-- End cs_slider --> </div><!-- End cs_wrapper --> </div><!-- End contentslider -->
To hold our article entries, we create another <div> element with class “cs_article”.
Inside each instance of cs_article, we’ll have a heading, an image, and a description, along with a link to read
the full entry. When all is said and done, each entry looks like this:
<div class="cs_article"> <h2> <a href="#">Article Number One</a> </h2> <a href="#"> <img src="images/article01.jpg" alt="Artist's interpretation of article headline" /> </a> <p> Hendrerit tincidunt vero vel eorum claritatem. Soluta legunt quod qui dolore typi. Vel dolore soluta qui odio non. Sollemnes minim eorum feugiat nihil nobis. Gothica dolor in legentis nihil quinta. </p> <p> Iriure parum autem putamus lectores duis. Quam sit quis me me zzril. Facer etiam in lectores hendrerit etiam. Exerci lorem liber tincidunt nostrud decima. Mutationem est zzril ipsum facer nobis. </p> <a href="#" class="readmore">Read More</a> </div><!-- End cs_article -->
Using this format, we’re able to add as many entries to the slider as we feel necessary.
To get our slider to function properly, we have to apply some styles to it. We’re going to use
a non-standard format in order to make customizing the CSS as easy as possible. Because the
JavaScript we’re going to write will control some of the styles, we’re going to split our CSS
into two sections: editable styles and non-editable styles.
First, let’s define our non-editable styles:
.contentslider {
position:relative;
display:block;
width:900px;
height:400px;
margin:0 auto;
overflow:hidden;
}
.cs_wrapper {
position:relative;
display:block;
width:100%;
height:100%;
margin:0;
padding:0;
overflow:hidden;
}
.cs_slider {
position:absolute;
width:10000px;
height:100%;
margin:0;
padding:0;
}
.cs_article {
float:left;
position:relative;
top:0;
left:0;
display:block;
width:900px;
height:400px;
margin:0 auto;
padding:0;
}
Above, we define the default size of the content slider and center it. Then, we
hide any overflow of the “cs_wrapper” and stretch the “cs_slider horizontally
to contain all of the entries. Finally, we set the “cs_article” class to float
left, allowing them to tile horizontally.
With the container elements set up properly, we can now style the inside of the
article container. We need to set up styles for our headline, image, description,
and “Read More” link.
.cs_article h2 {
display:block;
width:26%;
margin:10px 26px 5px 67%;
text-align:left;
}
.cs_article img {
position:absolute;
top:0;
left:0;
width:66%;
border:0;
-ms-interpolation-mode:bicubic;
}
.cs_article p {
display:block;
width:26%;
margin:0 26px 5px 67%;
padding:0;
border:0;
}
.cs_article .readmore {
display:block;
width:26%;
margin:0 26px 0 67%;
text-align:right;
}
Notice that width is defined with percentages, as is the right margin.
By doing so, we allow for the container to resize without losing the proportions
of our styles.
To round out our non-editable styles, we’ll define our buttons:
.cs_leftBtn, .cs_rightBtn {
position:absolute;
top:0;
height:400px;
padding:10px 0;
z-index:10000;
}
.cs_leftBtn {
left:0;
outline:0;
}
.cs_rightBtn {
right:0;
outline:0;
}
.cs_leftBtn img, .cs_rightBtn img {
border:0;
position:relative;
top:200px;
margin:0;
}
We set the z-index of the buttons to 10000 to prevent them from sitting
under the article previews, and then we remove the outline from clicked links.
To reduce the amount of markup necessary to achieve our desired effects, note
that we’ve declared our <a> tag as a block-level element.
Our editable styles are all fairly simple, and deal mostly with the colors and
fonts of our display.
.contentslider {
padding:10px; /* This acts as a border for the content slider */
background:#333; /* This is the color of said border */
}
.cs_wrapper, .cs_article {
background:#FFF; /* Background color for the entries */
}
.cs_leftBtn, .cs_rightBtn {
width:30px; /* Should be as wide as the button graphic being used */
background:#333; /* This will probably match the contentslider bg color */
}
.cs_article h2 {
font-size:200%;
line-height:1.125em;
}
.cs_article h2 a {
color:#333;
text-decoration:none;
}
.cs_article p {
font-size:85%;
line-height:1.5em;
color:#777;
}
.cs_article .readmore {
font-size:80%;
}
As indicated by the comments above, we’re using the padding on contentslider
as a border. This made more sense when considering the absolute positioning of
the buttons, because otherwise negative values would have been necessary, and that
complicates things unnecessarily.
Any properties can be added above, but keep in mind that box model tweaks may be
overwritten by the non-editable CSS (located lower in the stylesheet) or by the
jQuery plugin.
With our styles in place, the markup should look a little more presentable. Also,
because the buttons are added by the jQuery plugin, the slider degrades gracefully,
becoming a display box for just the first article.
With the slider styled and marked up properly, we can start adding jQuery effects!
(function($) {
$.fn.ContentSlider = function(options)
{
var defaults = {
leftBtn : 'images/cs_leftImg.jpg',
rightBtn : 'images/cs_rightImg.jpg',
width : '900px',
height : '400px',
speed : 400,
easing : 'easeOutQuad',
textResize : false,
IE_h2 : '26px',
IE_p : '11px'
}
// Declare variables here
// Process the content slider here
})(jQuery)
Our first task is to set up the plugin and declare default values. For this
plugin, we’ll allow the user to customize the images used for the buttons, the
width and height of the content slider, the animation speed, the easing formula,
whether or not the text will be resized by the plugin, and, because Internet
Explorer doesn’t seem to play nice with font-size, IE-specific font
sizes for the article heading and description.
Next we have to extend the default values with those supplied by the user, and
then we declare a handful of variables that will be used by the plugin:
var defaultWidth = defaults.width;
var o = $.extend(defaults, options); // Extend the defaults with user-defined values
var w = parseInt(o.width); // Removes the 'px' from the width option
var n = this.children('.cs_wrapper').children('.cs_slider').children('.cs_article').length;
var x = -1*w*n+w; // Minimum left value
var p = parseInt(o.width)/parseInt(defaultWidth); // Percentage of default size
var thisInstance = this.attr('id'); // The id of the content slider
var inuse = false; // Prevents colliding animations
The variables declared above may not make much sense right now, but we’ll get
to them in just a second.
Our next step is to cycle through all matched elements and make our content slider
interactive. We do this using the .each() method. First, we set the
width and height of the content slider and add the buttons:
return this.each(function() {
$(this)
// Set the width and height of the div to the defined size
.css({
width:o.width,
height:o.height
})
// Add the buttons to move left and right
.prepend('<a href="#" class="cs_leftBtn"><img src="'+o.leftBtn+'" /></a>')
.append('<a href="#" class="cs_rightBtn"><img src="'+o.rightBtn+'" /></a>')
Next, we need to set the article div to be the same size as the content slider.
// Dig down to the article div elements
.find('.cs_article')
// Set the width and height of the div to the defined size
.css({
width:o.width,
height:o.height
})
.end()
Finally, we set the opacity of the left button to zero, then hide the right
button and animate its entrance for a little bit of added style.
// Animate the entrance of the buttons
.find('.cs_leftBtn')
.css('opacity','0')
.end()
.find('.cs_rightBtn')
.hide()
.animate({ 'width':'show' });
With our buttons in place and the content slider properly sized, we now need
to resize the text (if the textResize flag is set to true).
First, we determine the current size of the text in the content slider and
store it in variables (h2FontSize and pFontSize)—or,
in the case of Internet Explorer, we just set the variables based on the
options passed at the creation of the plugin—and then set the new
size based on the product of our variables and the p variable set
above, which is the size in percent of the content slider after being resized.
// Resize the font to match the bounding box
if(o.textResize===true) {
var h2FontSize = $(this).find('h2').css('font-size');
var pFontSize = $(this).find('p').css('font-size');
$.each(jQuery.browser, function(i) {
if($.browser.msie) {
h2FontSize = o.IE_h2;
pFontSize = o.IE_p;
}
});
$(this).find('h2').css({ 'font-size' : parseFloat(h2FontSize)*p+'px', 'margin-left' : '66%' });
$(this).find('p').css({ 'font-size' : parseFloat(pFontSize)*p+'px', 'margin-left' : '66%' });
$(this).find('.readmore').css({ 'font-size' : parseFloat(pFontSize)*p+'px', 'margin-left' : '66%' });
}
Next, we have to tell the buttons what to do when they’re pressed. To keep
the code as concise as possible, we’re going to move the slider with a
function called moveSlider.
First, we store the button in a variable, and then bind an event to it that
fires on the “click” event. The click will set the inuse variable to
true, which will prevent multiple clicks from causing erratic behavior in the
slider, then fires the moveSlider function.
We repeat this for the right button, and finally run a quick function to
vertically center the buttons. Then we close our .each() call.
// Store a copy of the button in a variable to pass to moveSlider()
var leftBtn = $(this).children('.cs_leftBtn');
leftBtn.bind('click', function() {
if(inuse===false) {
inuse = true;
moveSlider('right', leftBtn);
}
return false; // Keep the link from firing
});
// Store a copy of the button in a variable to pass to moveSlider()
var rightBtn = $(this).children('.cs_rightBtn');
rightBtn.bind('click', function() {
if(inuse===false) {
inuse=true;
moveSlider('left', rightBtn);
}
return false; // Keep the link from firing
});
vCenterBtns($(this)); // This is a CSS fix function.
});
We now need to define the moveSlider function.
First, we determine the current left value of the “cs_slider” div,
setting it to zero if no value is currently set. Next, we determine how far the
div needs to move by either adding or subtracting the width of the content
slider, depending on which direction we’re moving.
function moveSlider(d, b)
{
var l = parseInt(b.siblings('.cs_wrapper').children('.cs_slider').css('left'));
if(isNaN(l)) {
var l = 0;
}
var m = (d=='left') ? l-w : l+w;
Next, we have to make sure the new left value is within the minimum and
maximum constraints, which prevent the content slider from sliding out of
view. If the new left value is within our constraints, we animate the
movement from the current value to the the value.
if(m< =0&amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;m>=x) {
b
.siblings('.cs_wrapper')
.children('.cs_slider')
.animate({ 'left':m+'px' }, o.speed, o.easing, function() {
inuse=false;
});
To wrap up this function, we want to hide the button if the slider can no
longer move in that direction. In order to do this, we have to first save the
buttons into variables (thisBtn and thatBtn).
if(b.attr('class')=='cs_leftBtn') {
var thisBtn = $('#'+thisInstance+' .cs_leftBtn');
var otherBtn = $('#'+thisInstance+' .cs_rightBtn');
} else {
var thisBtn = $('#'+thisInstance+' .cs_rightBtn');
var otherBtn = $('#'+thisInstance+' .cs_leftBtn');
}
Next, if the minimum or maximum left value has been reached, we fade out the
button that moves in that direction. Also, we check if the opposite button
from the one clicked is faded out, and fade it back in if so.
if(m==0||m==x) {
thisBtn.animate({ 'opacity':'0' }, { duration:o.speed, easing:o.easing });
}
if(otherBtn.css('opacity')=='0') {
otherBtn.animate({ 'opacity':'1' }, { duration:o.speed, easing:o.easing });
}
}
}
Our last step is to define the vCenterBtns function.
This function simply divides the plugin-defined height of the content slider and
divides it in half, then sets that as the top value of the button image.
function vCenterBtns(b)
{
// Safari and IE don't seem to like the CSS used to vertically center
// the buttons, so we'll force it with this function
var mid = parseInt(o.height)/2;
b
.find('.cs_leftBtn img').css({ 'top':mid+'px', 'padding':0 }).end()
.find('.cs_rightBtn img').css({ 'top':mid+'px', 'padding':0 });
}
With our jQuery in place, we now have a fully functional content slider!
Finally, to use the plugin, simply call the following:
<script type="text/javascript">
$('.contentslider').ContentSlider();
</script>
Any of the default options can be altered by simply passing a JSON object as
a parameter the ContentSlider():
<script type="text/javascript">
$('.contentslider').ContentSlider({
leftBtn: 'images/newLeftButton.jpg',
rightBtn: 'images/newRightButton.jpg',
width : '600px',
height : '240px',
speed : 600,
easing : 'easeInOutBack',
textResize : true,
IE_h2 : '30px',
IE_p : '14px'
});
</script>
As you can see in the demo,
this plugin supports multiple instances of itself, so if you feel the urge, you
could potentially put a thousand of these suckers on a page without incident.
As far as I can tell, this is supported by Firefox, Safari, Opera, and IE6+. Be
sure to point it out in the comments if you find browser bugs.
I attempted to keep all the cosmetic styling of the content slider accessible,
allowing for total customization of the plugin. If you spot a bug, have any
trouble with installation, or (preferred) you want to talk about how wonderful
you found this plugin, don’t hesitate to drop a comment below or
email me.
Posted in Web Programming | 64 Comments »
Monday, March 30th, 2009
Today we’ll be learning the gist of Django, a pythonic web framework. In the spirit of a stereotypical web framework tutorial, we’ll produce a primitive blog with the minimal amount of code possible. Yellow background color text indicates text to be entered into a command line/terminal and blue indicates code. If you’ve followed my django screencast, you’ll be familiar with the most of what this tutorial covers. However, I’ll explain the code in this tutorial in more depth than I did in the screencast. If you like to know what everything does, this article is for you.
If you’ve never dealt with (or even seen) python code before, I recommend skimming through python’s official tutorial. The most notable difference between python and most other languages is that tabs/spaces are used to indicate code blocks. So an if statement would look something like this:
if myvariable == True:
print “myvariable is True”
print “Always printed”
One other thing to note is that boolean variables are True and False (case-sensitive). It’s also a good idea to dust off your terminal / command line skills (cd, ls, etc.).
If you’ve followed another django tutorial, you’re all set. Otherwise here’s some brief steps to follow.
Alternatively, you could try using a DjangoStack installer, but I’ve never used one so I can’t say how easy or hard it is.
Unless you’ve been hiding under a rock or are completely new to the web development community, you know that Model-View-Controller (MVC), is the latest craze is the web world. This provides a clean separation among:
Django is quite similar, although it uses the name MTV (Model-Template-View) instead. This is slightly confusing for people coming from other MVC frameworks since a MVC Controller is a View in Django and a MVC View is a Template in Django. I’ll be referring to everything in terms of Django’s MTV in the remainder of the tutorial.
Django templates have their own template language which is relatively easy to grasp for programmers. It’s catered for web designers (not programmers) to manage logic that directly deals with how to display data. The templating system is designed to be as minimal as possible and specifically excludes any feature that doesn’t relate to the display logic (e.g. variable assignments are not allowed). Although the templating system could be extended to implement such features, most of that code really belongs in the view.
For more information, you can see the entire laundry list of Django’s philosophies.
I prefer to run instead of walk first, but that’s just me. Let’s create a django project using django-admin.py startproject myblog to create a myblog directory containing our django project.
What are these files?When you first create a project, you have the following files:
__init__.py tells python that this folder is a package which can be imported/included by other python packages. This allows the django framework to import our application for execution. This file only needs to exist for this effect. manage.py provides commands that django-admin.py provide with all the settings that are specified in settings.py. This allows you to do: python manage.py runserver to run the server for this project instead of having to add your project module to python’s module search paths and specify the settings.py file. urls.py describes the server mapping from urls to function calls, which ultimately result in a http response. URLs are mapped via regular expressions. settings.py contains project-related settings. This includes individual application setting parameters as well as global ones (such as database and timezone info). |
We’ll edit settings.py and enter our database information:
DATABASE_ENGINE = ’sqlite3′
DATABASE_USER = ’sqlite.db’
Fill in other database information if your database engine requires it (which is anything other than sqlite3). You can edit your TIME_ZONE to be closest to your server location (or your location if you’re running it locally), but it doesn’t really matter too much for us.
File paths in settings.py must be absolute. This is because a relative path isn’t explicit (one of python’s philosophies) since it could refer to either where django’s site-package location (where some provided addons reside) or your current working directory (where you executed the command to start the server) or your project directory. Instead paths are all absolute. Since we’re going to make all our relative paths relative to the project directory, or settings.py to be more precise, we’ll add the following code snippet to the top of our settings.py to automatically convert all our relative paths we specify to absolute paths.
import os
rel = lambda *x: os.path.join(os.path.abspath(os.path.dirname(__file__)), *x)
The first line imports the python-provided os module which provides us with path-related functionality.
The second line is a bit more complicated to gobble. We’re creating a lambda/anonymous function named rel. In python, lambda functions are usually short one-liner functions that have to return a value, which also explains the reason why there’s no return keyword (the expression is implicitly returned). As part of the lambda definition, we accept any amount of arguments which is stored in array x.
We then join a series of paths (which will figure out the appropriate directory separator based on the operating system) which includes the absolute path determined by the directory name where this file resides (settings.py) and any directories we provide in the function parameters. *x expands the x array and passes to the function as parameters.
Now we can provide relative directories from our project directory. Let’s specify those now in settings.py. Make the following changes (or change them to whatever you feel is right):
MEDIA_ROOT = rel(‘media’) # media subdirectory in the project directory
MEDIA_URL = ‘/resources/’ # for the variable we get to use in templates, later
TEMPLATE_DIRS = (
rel(‘templates’),
)
If you wanted all the media and templates in one directory you could do something like:
MEDIA_ROOT = rel(‘resources’, ‘media’)
MEDIA_URL = ‘/resources/’
TEMPLATE_DIRS = (
rel(‘resources’, ‘templates’),
)
Save, and we’re good for now.
What good is a blog without any posts? Our first application will provide the framework for a blog post. So in the project directory execute django-admin.py startproject posts or python manage.py startproject posts to create a subdirectory and application names posts.
The following files in the new directory are as listed:
Before we implement anything else, we should probably create the models for our app. Our post model is going to be minimalistic. So open up models.py and append the following:
from django.contrib.auth.models import User
class Post(models.Model):
author = models.ForeignKey(User, related_name=’posts’)
title = models.CharField(max_length=200)
body = models.TextField()
pub_date = models.DateTimeField(auto_now_add=True)
up_date = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.title
This is presents our data for our model which inherits from django’s Model class. The first line imports the django-provide User model, which adds users support for our project, including authentication and permissions. But in this case, we’re using it to associate a user who creates a post to be the author of it. The named key parameter related_name is the variable name the User model should have to store the list of posts. By default it is <model_name>_set, but here we’re specifying it as posts.
Each post will have a title field which is a database char field whose max length is 200. This is validated both via the database (assuming you use Django to create the tables) and by Django when the model is saved. The body field is self explanatory, create a field to store a large string of text. Pub_date and up_date store datetime fields in the database. The auto_now_add keyword parameter sets the field to the current date time when the model is being added to the database (not when saving changes). Likewise, auto_now applies the current datetime whenever the model is saved.
Finally, we have a __unicode__ method defined. This is simply a unicode string to return when a post instance is requested to be displayed automatically.
That’s all the models we need! ![]()
Next, we’ll need to add our application to our project. Add the following line to your INSTALLED_APPS variable in settings.py:
‘posts’, # whatever you named your application
So you INSTALLED_APPS should look something like this:
INSTALLED_APPS = (
’django.contrib.auth’,
’django.contrib.contenttypes’,
’django.contrib.sites’,
’posts’,
)
It is worth noting that applications are loading in order they are listed. So your applications should always be at the end since they’ll usually depend on Djangos’ built-in applications.
We can tell Django to create all the tables in INSTALLED_APPS based on what the models defined. This can be done with python manage.py syncdb.
When creating tables for django.contrib.auth, it asks you to create a superuser, do so since it’ll allow you to login in the admin interface we’ll be discussing in the next section.
We will be continuing Part II tomorrow so stay tuned by subscribing to the RSS Feed
Posted in Web Programming | 17 Comments »
Friday, March 27th, 2009
In today’s fast paced global economy, customers are looking for more convenient ways to shop for goods. As technology advances, more and more people are choosing to participate in e-commerce, or simply, they’re shopping online. E-commerce offers people the fastest way to shop for their desired products 24/7/365. You can shop for products from around the world at your convenience, delivered straight to your home.
Choosing to market your products through eCommerce could be one of the smartest decisions you’ve ever made for your small business. Online growth potential is unlimited, overhead is lower, and web analytics allow you to analyze the most intricate details of your website’s performance. You’re able to sell more products at lower prices which customers always appreciate. Currently more than 50% of all households in the USA have broadband access. This number, as well as your target online market, will only continue to grow.
What are your thoughts on eCommerce? If you have a minute also subscribe to our RSS!
Posted in Uncategorized | No Comments »
Tuesday, March 17th, 2009
I am pleased to say that I have done a guest blog post over at EnnuiDesign.com for a good friend of mine, Jason Lengstorf. I suggest you follow him on twitter. As well please subscribe to my RSS Feed…
In a recent project I was working on we had to allow the client to embed videos within the site. This had to be done using an easy-to-use customized CMS. The thought is that they can take the embed code right off the YouTube site and save it to the DB for use throughout the site.
View the complete article over at EnnuiDesign.com!
Posted in Uncategorized | No Comments »
Friday, March 6th, 2009
What is the occasion for such a giveaway you may ask; well it happens that this post will be my 100th post exactly! As well as this it has been pretty much been a year since I started sharing my knowledge with you, my readers!
It has been a hard journey at times, as most of you fellow bloggers can understand. A great deal of effort is put into promoting and writing the best content possible. This blog has evolved from originally having custom programming, to eventually moving to a more scalable WordPress with a ton of features already built-in.
Today I have for you two eBooks courtesy of my friends at Packt Publishing. The 2 eBooks you could get your hands on are:


All you have to do to have a chance at winning is leave a comment below stating which book you would like as well as a quick tip about either WordPress or jQuery. The winners will be announced in a week or two and will be chosen at random.
Note: Please leave a valid email as I will contact you here if you happen to win.
As always please subscribe to the RSS Feed as this is a measuring tool for the success of this blog.
Thanks to you my loyal readers, and let the winning begin!
Posted in Uncategorized | 101 Comments »
Twitter
Follow me on Twitter to keep up to date!
RSS Feed
Keep up with all of our updates by subscribing to our RSS feed!
FaceBook
Join our group on Facebook and become a fan of us!