'Add More' form fields with javascript / jquery

A few years ago I wrote a post on how to add more fields without reloading the page using javascript, but that method was kind of clunky and involved a hack to get it to work with the DOM.  The following is a much easier way, and (as far as I've tested) compatible with all major browsers.

First off, download the latest version of jquery and include it on your page, or just include the following line if you trust google to host your jquery file:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>

Here's a sample html form – adjust according to your needs:

<form action='mypage' method='post' accept-charset='utf-8'>    
 <ul id='myfields'>
  <li>
   <input type='text' name='mytextfield[]' /> 
  </li>
 </ul>
 <div id='addmorelink'>
  <a href='javascript:addField()'>add more</a>   
 </div>
</form>

What's important is the ul with the 'myfields' id, and the link that calls the 'addField()' js function.

The javascript code is very short and straightforward – basically copy your list item with the form field code into the content of the 'newContent' variable, make sure you escape quotes if you enclose the string with the same quotes as in your form field, and then use the jquery 'append' function to add the next field to your form, et voila, that's it!

<script type="text/javascript"> 
 function addField(){
  var newContent = "<li><input type='text' name='mytextfield[]'/></li>";
  $("#myfields").append(newContent); 
 }
</script>

I haven't mentioned one last piece that's going to come in handy on the server side where you're going to process the fields.  You probably noticed the [] brackets behind the field name in the form – that turns the field into an array.  On the server side, depending on what programming language you use, you just need to handle your post variable as an array – so to retrieve each value you'll need to loop through the array.  Assuming you're programming in php and you're not using a framework that handles post variables differently:

<?php
 if(isset($_POST['mytextfield'] &amp;&amp;  is_array($_POST['mytextfield']){
  foreach($_POST['mytextfield'] as $value){ 
   // do something with each $value 
  }
 } 
?>

[SOLVED] Ubuntu 11.10 Oneiric Ocelot upgrade: Waiting for Network Configuration

I upgraded my Ubuntu desktop yesterday from 10.04 to 11.10 and ran into some pretty significant problems.  If you get an error saying 'Waiting for Network Configuration', and it sits there until it finally goes on to a black page, then try the following:

CTRL+ALT+F1 should get you to the command line.  Do not try to get into the command line from the recovery option, or you will run into 'read only problems'.  From the command line, log in as root or a sudoer (your main user account should be in the group) and do the following things:

1. create directories /run and /run/lock,
2. move contents of /var/run into /run and /var/lock into /run/lock,
3. delete directories /var/run and /var/lock
4. create replacement simlinks; e.g. 'ln -s /run /var/run' and 'ln -s /run/lock /var/lock'

For less experienced users, you will need to type the following commands:

sudo mkdir /run
sudo mkdir /run/lock
sudo mv /var/run/* /run
sudo mv /var/lock/* /run/lock
sudo rm -rf /var/run
sudo rm -rf /var/lock
sudo rm -rf /run/dbus/*
ln -s /run /var/run
ln -s /run/lock /var/lock

After that reboot your computer:

sudo reboot

Ubuntu *should* now start up properly.

Creating an advertisement widget for external websites using JavaScript

If you work with Google Analytics or Google Adsense, you've undoubtedly worked with the little code bits they ask you to include in your website.  This tutorial will teach you how to create your own widget that people can include on their website by pasting a similar piece of javascript.

First off, you'll need to create a javascript file, accessible from 3rd party systems.  Typically you won't have to do anything for this – just make sure you can access the file from any browser and host with the http protocol.

1) The simple and easy (but limited) solution

So let's go ahead and create mywidget1.js, and tell it to output the string 'Hello World'.

document.write("hello world!");

Now, we'll write the code bit that will be included on the 3rd party sites:

<script type="text/javascript" 
src="https://www.kevindubois.com/demos/js/mywidget1.js"></script>

Simple, right?  If that satisfieds your needs, all the better, but most people will want a little more functionality.

Either way, you can see a demo for this one at https://www.kevindubois.com/demos/widget1.html (the js code is at https://www.kevindubois.com/demos/js/mywidget1.js)

There are ways to pass variables and there are ways to handle secure servers, so if that's what you're interested in, please continue to read!

2) The more advanced (but still pretty easy) solution:

The files stay the same, only the code within will get a little more chunky.  My sample will be based on the assumption that you're sending an advertisement widget to the 3rd party sites – but it really could be anything you want, just change the parameters in whatever you want.

Let's start with the 3rd party code this time.  We'll write the javascript tags again,  but this time we're not going to include the location to the js file in the tag but rather, we're going to tell the browser to write another javascript codebit from within the first javascript tag.  This is necessary to pass some parameters to the js file; and to write some code around secure sites (or not) issues:

<script type="text/javascript">
 referral_code = "MQI74";
 ad_code = "aa";
 ad_width = "200"; // optional
 var myHost = (("https:" == document.location.protocol) 
? "https://www." : "http://www."); document.write(unescape("%3Cscript src='" + myHost +  
"kevindubois.com/demos/js/mywidget2.js' type='text/javascript'%3E%3C/script%3E")); </script>

referral_code, ad_code and ad_width are parameters that are being sent to the js file.  myHost detects whether we're on a secure site or not, and will change the path to reflect that.  Note that this will only work if you have a secure certificate on your end too.  The reason why I included this, is because some browsers will return a warning on the 3rd party secure site if your js file is not secure, saying that some items on the site are not secure.  The html tags are being escaped ( < = %3C and > = %3E ) and then unescaped, because otherwise the browser will interpret these tags incorrectly.

Let's go back to the js file and add some more code to handle the parameters and the security:

Start the js file by figuring out the security again:

var myHost = (("https:" == document.location.protocol) ? 
"https://www." : "http://www.");

The parameters you passed are directly available, so you can start using them immediately. In my case, I added a switch statement to show different ads (sort of like google adsense, where you can show different ad sizes and types by changing the ad code).  Make sure you escape opening and closing tags because you will get problems with the browser interpreting things incorrectly.

var ad_code = ad_code ? ad_code : '1a';
var referral_code = referral_code ? referral_code : '000';
var ad_width = ad_width ? ad_width : 200;

// switch code to see what we want to serve up
switch(ad_code){

   case '1a':
     document.write(unescape("%3Cdiv  
style='width:"+ad_width+"px; font-family: verdana, arial, helvetica,  
sans-serif; cursor:pointer; font-size:11px;'%3E"));      document.write(unescape("%3Ca href='" + myHost + "kevindubois.com/index.php? 
referral="+referral_code+"' style='text-decoration:none;color:white'%3E"));      document.write(unescape("%3Cdiv style='border-top:5px solid #0F0442;  
width:"+ad_width+"px; background-color:#FF6204; color:#FFF; padding-bottom:10px '%3E"));      document.write(unescape("%3Cul%3E"));          document.write(unescape("%3Cli style='margin-left:-15px'%3EThis is a  
demo for %3Ca href='https://www.kevindubois.com/2009/11/16/creating-advertisement-widgets-for-3rd-party-websites'%3E 
https://www.kevindubois.com/2009/11/16/creating-advertisement-widgets-for-3rd-party-websites%3C/a%3E%3C/li%3E"));     document.write(unescape("%3Cli style='margin-left:-15px'%3bla bla bla%3C/li%3E"));     document.write(unescape("%3Cli style='margin-left:-15px'%3Ebla bla bla%3C/li%3E"));     document.write(unescape("%3Cli style='margin-left:-15px'%3Ebla bla bla%3C/li%3E"));     document.write(unescape("%3C/ul%3E  "));     document.write(unescape("%3Cdiv style='text-align:center;font-weight:bold; 
font-size:12px; '%3E LEARN MORE %3C/div%3E"));     document.write(unescape("%3C/div%3E"));     document.write(unescape("%3C/a%3E"));     document.write(unescape("%3C/div%3E")); break; case '2a': document.write(unescape("%3Cdiv style='width:"+ad_width+"px; font-family: 
verdana, arial, helvetica, sans-serif; cursor:pointer; font-size:11px;'%3E")); document.write(unescape("%3Ca href='" + myHost +  
"kevindubois.com/index.php?referral="+referral_code+"' style='text-decoration:none;color:white'%3E")); document.write(unescape("%3Cdiv style='border-top:5px solid #0F0442;  
width:"+ad_width+"px; background-color:#FF6204; color:#FFF; padding-bottom:10px '%3E")); document.write(unescape("%3Cul%3E"));     document.write(unescape("%3Cli style='margin-left:-15px'%3EThis is a demo for  
%3Ca href='https://www.kevindubois.com/2009/11/16/creating-advertisement-widgets-for-3rd-party-websites'%3Ehttps://www.kevindubois.com/2009/11/16/creating-advertisement-widgets-for-3rd-party-websites%3C/a%3E%3C/li%3E"));     document.write(unescape("%3Cli style='margin-left:-15px'%3bla bla bla%3C/li%3E"));     document.write(unescape("%3Cli style='margin-left:-15px'%3Ebla bla bla%3C/li%3E"));     document.write(unescape("%3Cli style='margin-left:-15px'%3Ebla bla bla%3C/li%3E"));     document.write(unescape("%3C/ul%3E  "));     document.write(unescape("%3Cdiv style='text-align:center;font-weight:bold;  
font-size:12px; '%3E LEARN MORE %3C/div%3E"));     document.write(unescape("%3C/div%3E"));     document.write(unescape("%3C/a%3E"));     document.write(unescape("%3C/div%3E")); break; // and so on ... }

The only thing I haven't mentioned is the links and the referral code: you can track widgets and clicks from each 3rd party by supplying a referral code. The link within the widget has this referral code and in the linked page you can then write some code to track/count/whatever you want.
From here on, I think you should have all the tools to start customizing your own widget. You can make everything even more dynamic by using some ajax; you can add more parameters or really any content you want.

You can find a demo for the 2nd widget at https://www.kevindubois.com/demos/widget2.html (the js code is at https://www.kevindubois.com/demos/js/mywidget2.js)

Database driven jQuery rotating slide show with text navigation and links using the cycle plugin

This tutorial will help you make a database driven slide show that has a navigation bar with text links to each slide, a pause button and the slides also have a database driven link.  I'll assume you know how to get the records in the database and how to read the php code because you will need to define the location of your images and get the code to connect to your database.

See a demo of this tutorial here

Download the source code (all crammed into 1 php file for your convenience).  You will also need jquery, the cycle plugin and optionally the easing plugins for jquery.

First, we'll need to create a folder with some images.  My folder is called slide_img and is a child folder of my php file.

We'll also need to create a table in the database:

CREATE TABLE `slide_items` (

`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`filename` VARCHAR( 200 ) NOT NULL ,
`title` VARCHAR( 50 ) NOT NULL ,
`link` VARCHAR( 500 ) NOT NULL ,

UNIQUE (`filename`)

) ENGINE = MYISAM

You'll probably want to insert some records – these are based on the images I have in my demo – but the filename should correspond with the filename of the images in your slide_img folder.  Typically you would sync this all up with an admin tool where you would have a form for the title and link and an upload field for the image, but that's out of the scope of this article.

INSERT INTO `slide_items` (

`id` ,`filename` ,`title` ,`link`

)
VALUES

(NULL , '1.jpg', 'glacier NP', 'https://www.kevindubois.com'),

(NULL , '2.jpg', 'Blodgett Canyon', 'http://www.duboistechnologies.com'),

(NULL , '3.jpg', 'Tree at Ridge', 'http://www.google.com'),

(NULL , '4.jpg', 'Sheep Mtn Bowl', 'https://www.kevindubois.com');

Now that we have the database and image folder set up, we can dive into the code.   The slide class contains all the database interactions, so let's start with that.  The class has 2 main functions: get_slides() retrieves the records from the database and show_slides() loops over the records and returns a variable that contains the html for all the images and their corresponding links.  For more detail, read the comments in the code:

class Slide{
// where are the images stored?
var $imgfolder      = "/demos/slide_img/";
var $dbconnection   = false;
// =============================================
// Method      : constructor
// Paramaters  : none
// Return Value: none
// Purpose     : instantiate the database connection
// Author      : Kevin Dubois
// =============================================
public function __construct()
{
// connect to database – replace the xxx with your database connection settings
$this->dbconnection = mysql_connect('xxxx', 'xxxxx', 'xxxxx') or die("Database Connection Failure");
mysql_select_db("xxxx", $this->dbconnection) or die("Database not found");

}

// =============================================
// Method      : destruct
// Paramaters  : none
// Return Value: none
// Purpose     : close the database connection
// Author      : Kevin Dubois
// =============================================
public function __destruct(){
// close db connection
mysql_close($this->dbconnection);
}

// =============================================
// Method      :  get_slides()
// Paramaters  :  none
// Return Value:  array slides: all database records
// Purpose     :  get all slides
// Author      :  Kevin Dubois
// =============================================
public function get_slides()
{
// get slides from db query
$query = "  SELECT id, filename, title, link
FROM slide_items
ORDER BY id ASC";
// send query to db
$result = mysql_query($query);
// define $slides
$slides = array();
// loop over the records and populate the slides array
while($row = mysql_fetch_assoc($result)){
$slides[] = $row;
}

return $slides;

}

public function show_slides(){
// get the slides from db
$files = $this->get_slides();
// define $file_links
$file_links = ";
// loop over db records and create the image html code
foreach($files as $file){
$file_links .= <<<EOD
<a href="{$file['link']}" id="{$file['filename']}" title="{$file['title']}">
<img alt="{$file['title']}"  src="..{$this->imgfolder}{$file['filename']}" />
</a>
EOD;
}

return $file_links;
}
}

Now that we have the functionality to retreive the images, we can start with the html (with just a tiny bit of php injected).   Basically, I'll call the various jquery files, call the cycle function and let the cycle plugin do most of the work.  I have also integrated a navigation menu that floats on top of the images.  The css is also right in the code for the sake of clarity in this article, but you should probably save it in a separate css file. Refer to inline comments for more detail, or comment on this article and I will do my best to reply asap.

<?php

// the slide class can either be imported with an include or simply pasted here

// call the slide class
$slide = new Slide();

// now print the html
?>

<!– Call jquery files –>
<script src="../js/jquery.js" type="text/javascript"></script>
<script src="../js/jquery.cycle.js" type="text/javascript"></script>
<script src="../js/jquery.easing.js" type="text/javascript"></script>

<script type="text/javascript">
$(document).ready(function(){
// make the background of the nav bar transparent
$("#slide-background").fadeTo(0,0.65);

// instantiate the slideshow
$('#slideshow').show();
// define the slideshow parameters (see http://malsup.com/jquery/cycle/ for more info)
$('#slideshow').cycle({
fx:         'scrollLeft',
timeout:     5000,
pager:      '#slidenav',
// callback fn that creates the links for navigation
pagerAnchorBuilder: function(idx, slide) {
return '<a href="#" style="font-size:9px">'+slide.title+'</a>';
},
pagerEvent: 'mouseover',
fastOnEvent: true,
fit:         1,
pause: 1,
pauseOnPagerHover: 1
});

// code for the pause button
$("#pbtn").click(function () {
var pbtn = $("#pbtn").html();
if(pbtn.toLowerCase() == '<a>||</a>'){
$("#slideshow").cycle('pause');
$("#pbtn").html('<a>&gt;</a>');
} else{
$("#slideshow").cycle('resume');
$("#pbtn").html('<a>||</a>');
}
});

// slide down the navigation links
$('#slide-text').slideDown();
});

</script>

<style type="text/css">
body{font-size:16px}
#slidenav { display:inline; line-height:20px }
#slidenav a { margin: 0.5em; padding: 0.5em 1em; text-decoration: none;color:#FFF  }
#slidenav a:hover{color:#FFF}
#pbtn a { margin: 0.5em; padding: 0.5em 1em;  text-decoration: none;  }
#slidenav a.activeSlide { background: #F00; color: #FFF }
#slidenav a:focus { outline: none; }
#pbtn a:focus { outline: none; }
.slideimg{width:50em; border:0}
.pics{display:none}
#pbtn{cursor: pointer; margin: 1em; display:inline; font-size:0.8em}

#slidenavmenu{position:relative;z-index:100; zoom:1}

#slide-background{
position:absolute;
top:21px;
background-color:#555;
width:50em;
left:0em;
font-size:1em;
line-height:20px;
}
#slide-text{
position:absolute;
width:50em;
left:0px;
text-align:center;
color:white;
top:20px;
padding-left:0.2em;
display:none;
font-weight:bold;
font-family: verdana, sans-serif;
font-size:1em;
}

</style>
</head>
<body>

<div id="slidenavmenu" >
<div id="slide-background">&nbsp;</div>
<div id="slide-text">
<div id="slidenav"></div>
<div id="pbtn" ><a>||</a></div>
</div>
</div>

<div id="slideshow">
<?=$slide->show_slides()?>
</div>

</body>
</html>

unless I forgot something, that's really all there is to it.  You can easily customize this widget to your pleasing – just make sure you sync up the filename of the images and the filename fields in the database table, and then play around with the css and the  jquery cycle settings, which you can find more information about on the cycle plugin site .  Let me know if you need me to explain anything in more detail, I know I haven't written too much detail but the comments in the code should really help to get the gist of it.

Curly Quote / Apostrophe in WordPress

When a user reported that some of my code snippets didn't work I noticed that the apostrophes in WordPress are automatically changed to curly quotes. That obviously breaks the code when php tries to parse it. I did some googling and found a simple solution: The "Unfancy Quotes" plugin which can be found here: http://www.semiologic.com/software/wp-tweaks/unfancy-quote/