Digital Thoughts

Alternative Syntax for Control Structures

Posted on: August 26th, 2013 by taff No Comments

 

PHP offers an alternative syntax, also known as colon syntax, for a number of control structures, including if, for, foreach and switch.

Here is an example of a nested foreach, if, else and switch using standard syntax.

Control Structures - Standard Syntax

$allowedExtensions = ["jpg", "gif", "png", "pdf"];
$filenames = ["test.jpg", "foo.gif", "temp.pdf", "spreadsheet.xls"];
foreach ($filenames as $filename){
$file_extn = substr($filename, strrpos($filename, '.')+1);
if ( true === in_array($file_extn, $allowedExtensions)){
switch( $file_extn ){
case "jpg":
case "gif":
case "png":
echo "Ohh ein Bildchen!";
break;
case "pdf":
echo "Ein PDF";
break;
}
echo "Output nach Switch";
}else{
echo "Dateityp verboten";
}
echo "Output nach if";
}

Using tabstops we can make this readable but what happens when the number of switch cases we need to check become so many that we need to scroll back up to see what structure opened the curly bracket we are currently looking at.

In my opinion using the alternative syntax makes it easier when browsing code to see where, what is closing.

Control Structures - Alternative Syntax

$allowedExtensions = ["jpg", "gif", "png", "pdf"];
$filenames = ["test.jpg", "foo.gif", "temp.pdf", "spreadsheet.xls"];
foreach ($filenames as $filename):
$file_extn = substr($filename, strrpos($filename, '.')+1);
if ( true === in_array($file_extn, $allowedExtensions)):
switch( $file_extn ): case "jpg":
case "gif":
case "png":
echo "Ohh ein Bildchen!";
break;
case "pdf":
echo "Ein PDF";
break;
endswitch;
echo "Output nach Switch";
else:
echo "Dateityp verboten";
endif;
echo "Output nach if";
endforeach;

It is important to point out that switch statements written in this format require the first case to be included with the statement. If you put the first case in a separate PHP block, you will get the following error:
Parse error: syntax error, unexpected T_INLINE_HTML, expecting T_ENDSWITCH or T_CASE or T_DEFAULT
I'm not sure exactly why PHP behaves this way, but it is a commonly made mistake that is not often explained or warned against.

You may want to find out more about the alternative Syntax

Resize iframe from another domain with easyXDM

Posted on: June 23rd, 2013 by taff No Comments

 

I recently ran into the problem of trying to resize an iframe element to match the height of the content. This does away with extra scrollbars which can create usability issues.
Unfortunately trying to resize iframe from another domain is not an easy task because of the same origin policy. However, there is normally a workaround for all things web and this is the solution I implemented to allow me to resize an iframe from another domain.

Although there are various ways to workaround the entire ajax / same origin policy headache I went with easyXDM and followed the resize iframe based on content example. The example worked as described but I then noticed the dreaded disclaimer "If you plan on navigating the inner window, be aware that this will break the connection and subsequent pages won’t cause the iframe to resize" and indeed this was the case. The suggested workaround was to use an intermediate iframe and an example was provided. Either this wasn't very well documented or I just didn't find it, so here is how I managed to resize iframe from another domain and navigate within it.

Document with the iframe

The document with the iframe had been built using JSF in this example.
The value of my hidden field with the id statisticsURL had been declared in a config file and was something like "http://www.someOtherDomainThanThisOne.com/page1.html"
The message being passed is the height of the content. I added 50 to the total height to ensure that scrollbars were not shown.

<form><input id="statisticsURL" type="hidden" value="#{sessionBean.statisticsURL}" /></form><script type="text/javascript">// <!&#91;CDATA&#91;
   var pageURL = encodeURIComponent($("#statisticsURL").val()); 			
   var transport = new easyXDM.Socket({ 				
      remote: "/iframe-intermediate.html?url="+pageURL, 				
      container: "iframeContainer", 				
      onMessage: function(message, origin){ 					
        message = (Number(message)+50); 					
        this.container.getElementsByTagName("iframe")&#91;0&#93;.style.height = message + "px"; 					
// &#93;&#93;></script>
<div id="iframeContainer"></div>

Intermediate iFrame to allow navigation from within the iframe and still be able to resize

Our intermediate iFrame is hosted at the same domain as our iFrame content i.e. www.someOtherDomainThanThisOne.com
In the example above it is called iframe-intermediate.html but the name plays no role whatsoever. The content of the intermediate iframe is:

<head>
        <script type="text/javascript" src="/path/to/easyXDM.min.js"></script>
        <script type="text/javascript">
            var iframe;
            var socket = new easyXDM.Socket({
                swf : "/path/to/easyxdm.swf",
                onReady : function() {
                    iframe = document.createElement("iframe");
                    iframe.frameBorder = 0;
                    document.body.appendChild(iframe);
                    iframe.src = easyXDM.query.url;

                    var timer;
                    iframe.onload = function() {
                        var d = iframe.contentWindow.document;
                        var originalHeight = d.body.clientHeight || d.body.offsetHeight || d.body.scrollHeight;

                        // We want to monitor the document for resize events in case of the use of accordions and such,
                        // but unfortunately only the window node emits the resize event, and we need the body's.
                        // The only solution then is to use polling..

                        // Lets start the polling if not all ready started
                        if(!timer) {
                            timer = setInterval(function() {
                                try {
                                    var d = iframe.contentWindow.document;
                                    var newHeight = d.body.clientHeight || d.body.offsetHeight || d.body.scrollHeight;
                                    if(newHeight != originalHeight) {
                                        // The height has changed since last we checked
                                        originalHeight = newHeight;
                                        socket.postMessage(originalHeight);
                                    }
                                } catch(e) {
                                    // We tried to read the property at some point when it wasn't available
                                }
                            }, 300);
                        }
                        // Send the first message
                        socket.postMessage(originalHeight);
                    };
                },
                onMessage : function(url, origin) {
                    iframe.src = url;
                }
            });

        </script>
        <style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                width: 100%;
                height: 100%;
            }
            iframe {
                width: 100%;
                height: 100%;
                border: 0px;
            }
        </style>
    </head>
    <body></body>

iFrame Content Example

This is example content to resize Iframe from another domain. The actual content of the iframe doesn't matter at all as in the example provided on the easyXDM website.

    <head>
        <title>easyXDM</title>
        <style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                background-color: green;
            }
        </style>
    </head>
    <body>
        <a href="resized_iframe_2.html">resized_iframe_2.html</a>
        <br/>
        Nam nulla nibh, tempus ut dictum eget, euismod vitae metus. Donec vitae nulla nec quam sagittis gravida vel quis eros. Nullam vel est justo. Donec euismod interdum magna, et rutrum libero tincidunt vel. Praesent imperdiet, magna et suscipit facilisis, nulla justo consequat nisl, et mollis elit nunc a est. Sed felis quam, condimentum eget gravida non, semper non quam. Duis vestibulum sem id erat tristique eleifend. Phasellus ante nunc, pulvinar nec facilisis at, hendrerit sed leo. Morbi lacinia nisl id nunc faucibus lacinia. Curabitur adipiscing leo a odio aliquet hendrerit. Nullam laoreet pulvinar suscipit.
    </body>

I spent a while trying to resize iframe from another domain until I finally managed to get it to work, so hopefully these examples will give you a good starter to workaround the same origin policy when you need to resize an iframe.

jquery each last iteration

Posted on: June 22nd, 2013 by taff No Comments

 

Rainer Sturm  / pixelio.de

Rainer Sturm / pixelio.de

I occasionally need to add some extra markup when looping through elements using jQuery each. The following is an example of some Javascript which I used to parse XML data that I received from an AJAX call. To cut down on overhead I don't use jquery .size() but prefered to use the "standard" .length property.

Get the last iteration of an each loop

The idea is simple to get the last iteration in the each loop, we simply find out how many elements we have in our array, loop through them, add one to our "counting" variable or incremental and check to see if we have reached the value of .length.

The example looks like this:

//get the length of our array
var totalLen = $(this).find('filename').length;

var tmpLen = 0;

$(this).find('filename').each(function(){
//add one each time the function is called
tmpLen++;
//add the content of our filename node
str += $(this).text();
//if it's the last element add a full stop, otherwse add a comma.
if(tmpLen<=totalLen){
str += ".";
}else{
str += ", ";
}
});

jQuery – Remove last row from table

Posted on: June 10th, 2013 by taff No Comments

 

Learning how to remove last row from table with javascript is functionality I occasionally implement when the last row contains totals for each column and I need to load more rows of data via ajax. I will delete the last table row then append data then call my total generator function.

If using jQuery I simply use the following to delete the last row from a table:

$('#idOfTable tr:last').remove();

Of late, whenever I use a table to display data I take advantage of the tablesorter plugin as it offers everything I need straight out of the box. The markup required by tablesorter for a table looks like this

<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td>Column 1</td>
<td>Column 2</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Footer 1</td>
<td>Footer 2</td>
</tr>
</tfoot>
</table>

As you can see I use the thead, tbody and tfoot tags. I think these are a good choice anyway so tablesorters requirement makes no difference to me at all.

Remove tfoot with jQuery

If I need to remove the entire tfoot before adding the new table rows it is even easier than the above script to remove a row. I can simply do

$('#idOfTable tbody').remove();

And it's bye bye tfoot.

 

I used the excellent jQuery tablesorter plugin yesterday to allow me to sort statistics being displayed in a table. The requirement was to be able to sort and export data in the currently sorted order to an Excel table. My method involved binding a function to the event when sorting ended. A simple

$("#idOfTable").tablesorter();

provided me with basic functionality and I was amazed at how fast the data was sorted. Excellent! the next stage was to restrict sorting so that one column could not be used to sort data. A simple update to

$("#idOfTable").tablesorter({
headers: {
2: {
sorter: false
}
}
});

This deactivates the header in the third column (the counter starts at 0).

Now the client wanted the ability to link and save sorted by a specific field.

The initial sort was carried out by the backend which, in this case was done in XSL.















We bind our function to manipulate the href of our export link (to add the parameters for the current sort order) as such:

$("#countries").bind("sortEnd",function() {
$('#countries thead tr th').each(
function(a){
var index=$(this).index();
var sortUp=$(this).is('.headerSortUp');
var sortDown=$(this).is('.headerSortDown');
var columnName = $(this).attr("name").toString().toLowerCase();
//Look to see which column currently has the sorting
if((sortUp == true)||(sortDown == true)){
switch(columnName){
case "country":
var columnSortName = "country";
break;
case "subscriber":
var columnSortName = "subscriber";
break;
case "total":
var columnSortName = "total";
break;
}
//Look to see which direction is currently being sorted
if(sortUp == true){
var sortDir = "&direction=descending"
}else if(sortDown == true){
var sortDir = "&direction=ascending"
}
var hashedURL="http://www.domain.com/exportLink?"
countriesParams = sortDir+"&countriesSort="+columnSortName;
//Change the href of our export link
$("#exportLnk").attr("href",hashedURL+countriesParams);
}
}
);
});

The function above is bound to the sortEnd Event provided by the tablesorter plugin, meaning that anytime the table is sorted the function is executed.
I'm using the classes added to the headers by tablesorter to ascertain whether the sort direction is ascending or descending. Using the .each loop I can also find out which column is being sorted by. This required a slight change to my normal table markup by adding a name attribute to the table header. the last stage rewrites the href of the URL to point to our export page with the current sort parameters. Simples

JQuery colour alternate table rows

Posted on: June 7th, 2013 by taff No Comments

 

Colouring alternate table rows increases readability, thus increasing usability. In particular long table rows with the same background colour being hard to read is a phenomenon that most of us know well from using MS Excel. The same goes for long tables in our browser where, in a worst case, we need to scroll the entire view.

Using jQuery to colour alternate table rows may sound strange when CSS now offers exactly that with the use of a pseudo selector.

Colour alternate table rows with CSS pseudo selector

tr:nth-child(even) {
background-color: #f8f8f8;
}

Unfortunately, and probably not that surprising for most of you, Internet Explorer 8 doesn't like the css solution. I am currently building an MIS for a large company and their browser of choice at the moment is, yes you guessed it, IE8 so I had to resort to a javascript solution. JQuery was already in use so I simply did the following

Colour alternate table rows with jQuery

$("tr:even").css("background-color", "#f8f8f8");

If I for whatver reason have no default background colour for my table rows I can use a short hand version of the if / else conditional like this

$("#idOgTable tbody tr").css("background-color", function(index) {
return index%2==0?"#f8f8f8":"#ffffff";
});

Due to my table setup using thead, tbody and tfoot tags I have the tbody in the selector. I needed this setup to allow me to use the amazing tablesorter plugin to exclude rows when sorting.

I hope you can use the above script to colour alternate table rows with jQuery.

tablesorter jQuery – how to exclude rows

Posted on: May 10th, 2013 by taff 8 Comments

 

The tablesorter plugin from jQuery is great when I have some data which I want to sort.

Calling

$("#tmp").tablesorter();

would allow me to sort markup such as by clicking on the headers:

<table class="tablesorter" id="tmp">
	<thead>
		<tr>
			<th>Area</th>
			<th>Total Visitors</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>Javascript</td>
			<td>15</td>
		</tr>
		<tr>
			<td>PHP</td>
			<td>3</td>
		</tr>
		<tr>
			<td>HTML5</td>
			<td>32</td>
		</tr>
		<tr>
			<td>CSS</td>
			<td>14</td>
		</tr>
		<tr>
			<td>XML</td>
			<td>54</td>
		</tr>
		<tr>
			<td><strong>Total</strong></td>
			<td><strong>118</strong></td>
		</tr>
	</tbody>
</table>

Easy peasy...No wait, I dont like how it is sorting the totals which are bold.
Sorting the Total Visitors row only would make it better and I could accomplish it by changing my javascript tablesorter call to

$("#tmp").tablesorter({
	headers: { 
		1: { 
			sorter: false 
		} 
	} 
});

which disables clicking of the second field (1 is the second field here, as 0 is the first, thus disabling a column. This makes it a little tidier but not really what we want. Ideally we want it to sort all the rows but leave the last one alone.

Not including the last row when sorting

I looked online and found a plugin which allows for static data whilst sorting.
Sounds like a little bit of an overkill for our example so I looked at how tablesorter works. The HTML needs to have a specific setup with thead and tbody tags.
So theoretically I could put my last row into a tfoot tag and it wouldnt be affected by sorting. So off I went and updated my markup to

<table class="tablesorter" id="tmp">
	<thead>
		<tr>
			<th>Area</th>
			<th>Total Visitors</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>Javascript</td>
			<td>15</td>
		</tr>
		<tr>
			<td>PHP</td>
			<td>3</td>
		</tr>
		<tr>
			<td>HTML5</td>
			<td>32</td>
		</tr>
		<tr>
			<td>CSS</td>
			<td>14</td>
		</tr>
		<tr>
			<td>XML</td>
			<td>54</td>
		</tr>
	</tbody>
	<tfoot>
		<tr>
			<td><strong>Total</strong></td>
			<td><strong>118</strong></td>
		</tr>
	</tfoot>
</table>

and hey presto it works. I hope this comes in handy for someone trying to sort columns with the jQuery tablesorter plugin apart from the last one(s).

 

Adding jQuery validation rules is one of the things that makes it my choice for client-side validation. There are lots of rules built into the plugin out of the box and you can add a new validation rule method easily. Occasionally however, whether a field is required, is dependent upon either the value of another field element, if a particular radio button or dropdown entry is selected or a checkbox is checked. For example an address may only be required if the send me the newsletter by post checkbox has been checked.

jQuery validation rules - depends

Fortunately the jQuery validation plugin allows for such occurences. To make a field only required if another field meets a certain criteria we use "depends" in the following way:

rules: {
address: {
required: {
depends: function(element) {
if ($('#newsletterByPost').is(':checked')){
return true;
}else{
return false;
}
}
}
}
}

As you can see we have our rules object which has the rule for the address field. required:true is how we do it to make the field always required. For a depends rule we simply add a depends which contains a conditional to find out if the checkbox has been checked. This is just a short example of how jQuery Validation rules work in conjunction with depends. There is literally no limit to the number of fields that are checked, you just need to make sure the returned value of the function returns a boolean value i.e. true or false.

Reset form elements with jQuery

Posted on: November 8th, 2012 by taff No Comments

 

Reset form with jQuery is not as easy as I thought. I was using some jQuery love to send some form values via AJAX to a service when the submit button was clicked. I like to override submits with javascript, it slows down spam when used on contact forms and the like and is very fast to implement. The basic idea is on submit, hide the form and submit the data using the jQuery serialize() method. If the data is successfully submitted offer the user the option of resubmitting the form. If they click on the link, stop hiding the form and reset the fields so as to avoid confusion. I will add a post on how to submit a form with jQuery in the near future, but I am digressing, so back to the example. This was my first attempt and it failed miserably.

//Fails miserably
$("#create_teaser").reset();

After looking online there was quite a bit of talk about creating new jQuery methods and such, which seemed like a bit of an overkill to me.

Example of reset form with jQuery

This solution is about as simple as it gets when you want to reset form elements.

$("#create_teaser")[0].reset();

Reset form elements with Javascript

If you don't have jQuery available then you could just reset a form like this:

document.getElementById('myForm').reset();

which gets the element with the id myForm (in our case the form itself) and resets all the form elements to their original value.

confirm delete prior to execution with javascript

Posted on: November 8th, 2012 by taff No Comments

 

Using javascript to confirm delete action is an important factor before carrying out data deletion. It gives you a second chance if you or the baby you have on your lap click on a delete button or link accidentally. In my opinion you should always have to confirm delete actions prior to execution.

Confirm delete - A javascript example

This is an example of a function to confirm a delete action. It uses jQuery for the selectors and AJAX calls. It also uses the jQuery live method so that content loaded at a later date can still be targeted by using selectors.

$(".deleteTeaser").live("click", function(){
//element ID is equal to the teaser ID: <button class=\"deleteTeaser\" id="12">Delete Teaser</button>
	var buttonID = $(this).attr("id");
	if(confirm("Are you sure you want to delete the teaser with id '"+buttonID+"'?")){
		$.ajax({
			type: "GET",
			url: '/link/to/delete/service/deleteTeaser',
			data: "teaserId="+buttonID,
			success: function (response) {
			  //Response from Service
			  if ($(response).find("status").text() == 'true') {
				//Action on success
			  } 
			}
		});


	}
});