Friday, May 31, 2013

innerHTML Property in HTML Elements

With this property, we can get or set the inner HTML/Contents of any elements. We have the following HTML ::

<div id='myDiv'></div>

Now if we write the following script, it successfully inserts a new HTML inside the above DIV. And this works on all versions of browsers.

<script> 
var p = document.getElementById("myDiv");
// Set the innerHTML
p.innerHTML = "<p>This is a nice day</p>";
</script>

 

Problem starts when we try to insert <link> or <style> elements through this innerHTML property. However, <link> tag should appear inside the <head> tag. So, let's re-write our program as shown below ..

<html>
<head id='header'>
<script> 
function load_style()
{
  var p = document.getElementById("header");
  var t = p.innerHTML;
  p.innerHTML =  "<link href='style.css' rel='stylesheet' >" + t;
}
</script>
</head>

<body>
<div id="mydiv">This is a sample DIV. Click the button to make this DIV Red
<input type="button" onclick="load_style()" value="Load Style">
</div>

</body>
</html>

 



The <head> element contains a script which inserts a new <link> tag inside the <head> and as a result, a stylesheet is loaded at run time. Check that the DIV contents change to red when the "Load Style" button is clicked. This works perfectly on all browsers but shows error on IE. Similar error occurs in IE when we try to insert new HTML inside any <tbody> element. For IE, "The innerHTML property is read-only on the col, colGroup, frameSet, html, head, style, table, tBody, tFoot, tHead, title, and tr objects" - ;MSDN. This has been done for security puposes. So, we need to use DOM methods to insert this new <link> tag inside the <head> element. Check the new implementation below ::

<script> 
function load_style()
{
  var p = document.getElementById("header");
 
  /* Create New link element */
  var t = document.createElement("link");

  /* Set href and rel property */
  t.setAttribute('href','style.css');
  t.setAttribute('rel','stylesheet');

  /* Append it to head tag */
  p.appendChild( t );
}
</script>


The above solution works on all browsers including IE7 and IE8. This dynamically loads a stylesheet and applies it.

Let's load some Javascripts using innerHTML property. Try the following function :

<script>
function load_script()
{
  var p = document.getElementById("header");
  var t = p.innerHTML;
  p.innerHTML =  "<script>alert('This is a nice day');</script>" + t;
}
</script>


The above function does not work because of malformed Javascript due to the existence of "</script>" word used inside the function body. Browser thinks that the script ends there. So the rest part " + t }" are assumed to be HTML and printed on screen. So, we would correct that first. Check out the implementation below ::

<html>
<head id='header'>
<script> 
function load_script()
{
  // Get the ID of <head>
  var p = document.getElementById("header");
  var t = p.innerHTML;
  p.innerHTML =  "<script>alert('This is a nice day');</scri" + "pt>" + t;
}
</script>
</head>

<body>
<div id="mydiv">This is a sample DIV. Click the button to load a script <br />
<input type="button" onclick="load_script()" value="Load Script">
</div>
</body>
</html>


Notice how the "</script>" has been written as "</scri" + "pt>" to tell JavaScript engine that this is just a string. The above code successfully inserts a new <script> node on all browser [Except IE] but does not execute the script. IF we insert the <script> tag in any other elements like DIV or P, it would have worked in IE also, but the code would still behave as a plain text.

However, dynamically adding a script to DIV or P etc elements does not make the new script work on any browser. However in IE, we can see a different bahaviour if we use the keyword "defer" on <script> tag.

<html>
<head id='header'>
<script> 
function load_script()
{
  // Get the ID of DIV
  var p = document.getElementById("mydiv");
  var t = p.innerHTML;

  // We use defer keyword
  p.innerHTML =  "<script defer>alert('This is a nice day');</scri" + "pt>" + t;
}
</script>
</head>

<body>
<div id="mydiv">This is a sample DIV. Click the button to load a script <br />
<input type="button" onclick="load_script()" value="Load Script">
</div>
</body>
</html>


The above code works on IE only. As soon as we click on the 'Load Script' button, a script tag with alert() function call is inserted in the "mydiv" DIV element and the script is executed.The keyword "defer" means the loading of JS is deferred.

So, we need to use DOM methods to insert a script.

<script>
function load_script()
{
  // Get the ID of head
  var p = document.getElementById("header");
 
  // Create new script element
  var scr = document.createElement("script");
 
  // Define Code Body
  var code = "function d(){ var sum = 0; "   +
     "  for(var i=1; i<=10; i++ )  sum += i;" +  

     "  alert('The Sum is : ' + sum );} d();" ;
        
  // Create a TEXT node
  var c = document.createTextNode(code);

  // Append the code to script
  scr.appendChild( c );

  // Append the script to header
  p.appendChild( scr );

}
 
</script> 

The above code successfully inserts a script at runtime inside the <head> tag. The script contains definition of a user-defined function d() which calculates sum of first 10 natural numbers and shows the sum on screen. And then we call the function d(). As a result, when we click on the "Load Script" button, the new script is appended to <head> element, the d() function is evaluated and run; so we see a message "The Sum is : 55" popping up on screen.

innerHTML property treats the inserted javascript statements as plain text. However, we can use eval() function to make those statements back to Javascript. Check the example below ..

<script> 
function load_script()
{
  eval( document.getElementById("mydiv").innerHTML  );
}
</script>

<div id="mydiv">function sum(a,b){alert (a+b);}</div>
<input type="button" onclick="load_script()" value="Load Script">
<input type='button' value = 'Get Sum' onclick='sum(1,2)'>


The purpose is, when the "Load Script" button is clicked, the content of the DIV is parsed and evaluated and as a result function sum() is registered, hence when then "Get Sum" button is clicked, the sum(1,2) function should get executed. But problem is this does not work as eval() maintains the scope for the code body it parses. Hence, the sum() function is registered inside the load_script() function only, hence not accessible form outside the parent function load_script(). So, if we change the DIV content as shown below, a function is registered in global scope and can be accessed from anywhere.

<div id="mydiv">sum = function(a,b){alert (a+b);}</div>

Here, we create a sum() function in the global scope. Hence the "Get Sum" button now works and shows us a message containing sum of 1 and 2.

We can receive block of Javascript statements in Ajax Response, put those statement texts in any DIV or span or other elements through innerHTML property of that element and then use eval() method to parse and evaluate them to do some automated job.


Check my next article "Dynamic JS Insertion" where I have discussed some more on this.

Wednesday, May 29, 2013

String Reversing with C

We need to write a C program which would reverse every word in a given sentence. For example if the given string is "India is my country", the resultant output would be "aidnI si ym yrtnuoc".

Going to solve the whole problem right now, let's try a small string reversing program which would reverse whole of a given string instead of reversing each word in it.

#include "stdio.h"
#include "string.h"
main()
{

  char str[35] = "Program" ;
 
  /* Print Before Reversing */
  printf("\n str : %s\n",str);

  /* reverse in Place */
  str_rev(str);

  /* Print AFter Reversing */
  printf("\n Reversed str : %s\n",str);
}

/* String Reversing Function.  It does
   not work on a copy of the string

*/
str_rev( char *str)
{
  int count = strlen(str);
  int j = 0, k=count-1, l = 0;
  char ch;
  while( l < count/2)
  {
      /* character swapping */
      ch = str[j];
      str[j] = str[k];
      str[k] = ch;
     
      /* Counters */
      j++; k--; l++;
    }
}


The Output :: "margorP"

Now check how the str_rev function works. To reverse a word "Program" to "margorP", we need a loop which would run from 0 index to the exactly middle of the string.

Word length : 7 [ index 0 to 6 ]
1st pass : swap between position 0 and 6 => mrograP
2nd pass : swap between position 1 and 5 => maogrrP
3rd pass : swap between position 2 and 4 => margorP

The character at position 3 does not need to be swapped with anything. See that we have already achieved the target, hence we need to stop here, if we go ahead, the swapping will again take place like this

4th pass : swap between position 3 and 3 => margorP
5th pass : swap between position 4 and 2 => maogrrP
6th pass : swap between position 5 and 1 => mrograP
7th pass : swap between position 6 and 0 => Program

The last 4 passes would get the original string "Program" back which we do not want. Hence, we need to run the main loop till half of the length of the string. The statement "while( l < count/2)" inside str_rev() function does just that. The function str_rev() takes a pointer to a string which means the string is updated in place. It does not work on a copy of the string.

Next, we would try to identify and print each word in a given string.

#include "stdio.h"
#include "string.h"
main()
{

  char str[35] = "  C   is   Nice   " ;
  int i,len, letter_found ;

  len = strlen(str);
  i = 0 ;
 
  while(1)
  {
    /* This Loop below only work if it
       is a non-whitespace character

    */
    letter_found = 0;

    while(str[i] && str[i]!=' ')
    {
      printf("[%c]",str[i]);
      i++;
     
      /* Set a flag that we found some letters */
      letter_found = 1;
    }
   
    /* Break if string ends */
    if( str[i] == '\0' )
     break;
    i++;
   
    /* Print a Newline after a word is printed */
    if(letter_found) printf("\n");

  }
  
}


The output of above program is :

[C]
[i][s]
[N][i][c][e]

The above program beautifully ignores all whitespaces and shows only the non-whitespace characters found inside the string. We need the inner loop to go through a single word and print it completely. After the inner loop ends, we check for string termination and if the string does not end here we again start at the beginning of outer loop. The outer loop while(1) keeps us going with printing every word and only when the string termination character '\0' is found, we break out.

Within the inner loop, we can copy every single word to another temp array and then reverse that temp array and print.

#include "stdio.h"
#include "string.h"
main()
{

  char str[35] = "  C   is   Nice   " ;
  char temp[35];
  int i, j, letter_found ;

  i = 0 ;
  /* Outer Loop Starts */ 
  while(1)
  {
   
    j = 0;
    letter_found = 0;

    /* This Loop below only work if it
       is a non-whitespace character

    */
   
    while(str[i] && str[i]!=' ')
    {
      /* Copy to temp Array */
      temp[j++] = str[i++];
     
      /* Set a flag that we found some letters */
      letter_found = 1;
    }

    /* terminate the "temp" string */
    temp[j] = 0;

    /* a word is found */
    if(letter_found)
    {

        /* Reverse the "temp" string */
        str_rev(temp);

        /* PRINT the "temp" string */
        printf("[%s]",temp);
    }
   
    /* Break if string ends */
    if( str[i] == '\0' )
     break;
   
    /* Counter */
    i++;

  }
  
}

/* Our old String Reversing function */
str_rev( char *str)
{

  int count = strlen(str);
  int j = 0, k=count-1, l = 0;
  char ch;
  while( l < count/2)
  {
      /* character swapping */
      ch = str[j];
      str[j] = str[k];
      str[k] = ch;
     
      /* Counters */
      j++; k--; l++;
    }
}



The output is given below :

[C][si][eciN]

The code above is quite self-explanatory. We put all the read characters in array "temp" and then calling our old function str_rev() on it. 


Next, the final goal, let's reverse all words within a given string. So, we won't take help of any temp array in this. To reverse a word, we need to know its start position and end position and then we would apply the logic we used in str_rev() earlier. Check out the implementation below ::

#include "stdio.h"
main()
{

  char str[35] = "    AB ABC     ABCD  ABCDE   " ;
  int i, j, k, l, letter_found, start_pos, end_pos ;

  i = 0 ;

  /* Outer Loop Starts */ 
  while(1)
  {
   
    letter_found = 0;

    /* This Loop below only work if it
       is a non-whitespace character

    */
   
    while(str[i] && str[i]!=' ')
    {
      if( letter_found == 0 )
      {
        /* Set a flag that we found some letters */
        letter_found = 1;
       
        /* Capture the start position */
        start_pos = i;
      }
      i++;
    }

    /* a word is found */
    if(letter_found)
    {

        /* Capture the end position */
        end_pos = i-1;

        /* NOW REVERSE */
        int count = end_pos - start_pos + 1;
        char ch;
        j = start_pos, k=end_pos; l = 0;

        while( l < count/2)
        {
          /* character swapping */
          ch = str[j];
          str[j] = str[k];
          str[k] = ch;
         
          /* Counters */
          j++; k--; l++;
        }
       
    }
   
    /* Break if string ends */
    if( str[i] == '\0' )
     break;
   
    /* Counter */
    i++;

  } /* Outer Loop Ends */

  /* Now PRINT The original String */
  printf("\n [%s]",str);
  
}


The output is shown below ::
[    BA CBA     DCBA  EDCBA   ]

The stating and trailing whitespaces are maintained as this reverses each word in a given string ignoring the whitespaces.

Tuesday, May 28, 2013

String trimming with C

Trimming means removing whitespaces from beginning and end of a string. First we would write a function which removes all trailing whitespaces from a given string.

The logic is ::

i) Scan a string from right end in a loop
ii) If a whitespace found at location n and location n-1 holds any non-whitespace, then we put a '\0' NULL character there and stop.
iii) Otherwise for every whitespace, we replace it with a NULL character.

#include"stdio.h"
#include"string.h"
main()
{
  char str[35] = "  India  is my   country  " ;
 
  /* TRIM end whitespaces */
  right_trim(str); 
 
  /* Print After right Trimming*/
  printf("\n %s",str);
}


/* Right Trim function definition */
right_trim(char *str)
{
  int i,len;
  len = strlen(str);
  i = len - 1;
 
  /* Make sure STRING is not empty */
  if( len > 0 )
  {

       /* This Loop scans the string from end */
       while(str[i])
       {
         /* If a space is found at nth position
            and n-1 position holds a character
*/
         if( str[i] == ' ' && str[i-1]!=' ' && i > 0 )
         {
           str[i] = 0;

           /* BREAK THE LOOP - Important*/
           break;
         }
         else if( str[i] == ' ' )
         {
            str[i] = 0;
         }
               
         i--;
       }
   
   }
}


The right_trim() function takes a pointer to a string which means it works on the original string, not a copy of it. There is a main loop which scans a given string from right end and it places a NULL character at any position if the following conditions satisfy..

a. If any whitespace is found and its previous character is a non-whitespace, then we can assume that it is end of the word/string, hence we put a NULL character at that position.

Suppose we have a string "PHP  " (2 whitespaces at the end) with character 'P' at index 0 and ' ' (space) at index 3 and 4. When the loop scans the string from the end (From index 4), in the first pass, the condition "str[i] == ' '" is evaluated to be true, hence a NULL is placed at position 4. In the second pass the condition " str[i] == ' ' && str[i-1]!=' ' && i > 0 "  becomes true and null character is placed at position 3 making the string "PHP". After this point, we should break out of the loop.

For another example string "Nice PHP  " (2 spaces at the end), after it puts '\0' at 8th position when condition " str[i] == ' ' && str[i-1]!=' ' && i > 0" (i=8) satisfies, if we don't break the loop, it satisfies the similar condition at position 4 and puts a '\0' at 4th position making the string "Nice" which is not what we want.

b. The else part's condition  str[i] == ' ' is equally important to right-trim empty string like  "    ". It continuously places a '\0' on every occurrence of whitespaces.

Now check out how to left-trim a given string like "   NICE PHP   " with 3 whitespace at both front and end. Here is the logic ::

i)Start scanning the string from beginning
ii) If a position has whitespace (" ") and next character is a non-whitespace, break the loop. That is the valid starting point of the string. We can copy from this position into another array or the same array
iii) Else we keep putting 0 in every position if it is a whitespace.

The step (iii) is for trimming empty strings like "  " (2 whitespaces). Now check the implementation below ..
   
#include"stdio.h"
#include"string.h"
main()
{

  char str[35] = "  NICE PHP  " ;
 
  /* TRIM beginning whitespaces */
  left_trim(str); 
 
  /* Print After LEFT Trimming */
  printf("\n %s",str);
}


/* LEFT Trim function definition */
left_trim(char *str)
{
  int i,len, copy_flag=0;
  len = strlen(str);
  i = 0;
 
  /* Make sure STRING is not empty */
  if( len > 0  )
  {

       /* This Loop scans the string from beginning */
       while(str[i])
       {
         /* If a space is found at nth position
            and n+1 position holds a character
*/
         if( str[i] == ' ' && str[i+1]!=' ' && i < len-1 )
         {

           /* Set the FLAG to denote that Shifting/Copying is required */
           copy_flag = 1; 

           /* BREAK THE LOOP - Important */
           break;
         }
         else if( str[i] == ' ' )
         {
            str[i] = 0;
         }
               
         i++;
       }
   
   }
   

   /* LEft Shifting is required */
   if( copy_flag )
   {
      /* i+1 holds valid start of the string as
         prior to that, all position holds whitespaces

      */
      int fpos = i+1;
      int target_pos = 0;
     
      /* start shifting the string towards left */
      while( str[fpos] )
      {
        /* Write/Shift */
        str[target_pos] = str[fpos];

        target_pos++;
        fpos++;
      }
     
      /* Denote new ending */
      str[target_pos] = 0;

   }

}


The loop while(str[i]) determines where the first non-whitespace character appears within the string. If any such non-whitespace character is found, its location is stored and we beak out the loop with a flag set to denote that the array values need to be shifted towards left. Then we shift the array towards left. If any non-whitespace character is not found, '\0' is inserted at every position which does not cause any harm. For example a string is "  NICE PHP  " (with 2 spaces at the beginning and end), in the 2nd pass of the loop the string becomes "0 NICE PHP  " as the first position gets a '\0' due to the code block :

else if( str[i] == ' ' )
{
  str[i] = 0;
}


The above condition satisfies when the i has a value of 0. But it does not harm because rest of the string "NICE PHP  " are shifted towards left and such NULL characters are over-written.

This was a very lengthy approach, let's take another small approach to left trim a given string. Here we would keep on left shift array characters until the first character becomes a non-whitespace character. Check the implementation below.

#include"stdio.h"
#include"string.h"
main()
{

  char str[35] = "  NICE PHP  " ;
 
  /* TRIM beginning whitespaces */
  left_trim(str); 
 
  /* Print After LEFT Trimming */
  printf("\n %s",str);
}


/* LEFT Trim function definition */
left_trim(char *str)
{
        int i=0, j , len;
      
       /* This Loop scans only the 1st position */
       while(  strlen( str ) > 0 && str[0] == ' ')
       {
           len = strlen( str );
           /* Put a NULL at 0 position */
           str[0] = '\0';

           /* LEFT Shift array characters */
           j = 1;
           while( str[j] )
           {
             str[j-1] = str[j];
             j++;
           }
         
           /* Denote End of the string */
           str[j-1] = 0;
           
       }
}


The 2nd approach requires less lines of code and easy to understand. The output is "NICE PHP  ".

Monday, May 27, 2013

Generate RSS feed with PHP

Generating RSS feed with PHP is vey easy. We need to maintain the basic RSS XML format in the output.

<?xml version='1.0' encoding='UTF-8'?>
<rss version='2.0'>
<channel>
<title> Any Title</title>
<link> Any URL </link>
<description> Any Description </description>
<lastBuildDate> Last Build Date</lastBuildDate>
<atom:link href="http://example.com/rss.xml" rel="self" type="application/rss+xml" />
<language>en-us</language>

<item>
<title> Item1 Title</title>
<link> Item1 URL </link>
<description> Item1 Description </description>
</item>

<item>
<title> Item2 Title</title>
<link> Item2 URL </link>
<description> Item2 Description </description>
</item>

</channel>
</rss>


The above XML shows two feed items enclosed within "<item>" tags and each item has its own "title", "link" and "description" tags. The whole item-node construct is enclosed in <channel> and <rss> tags which is important. The "<atom:link ...." tag is totally optional and it's href property should hold the URL of current feed. Using such "<atom:link>" tag has some advantage of being portable and easier to cache. RSS 2.0 requires "title", "link" and "description" tags to be present in the output whereas Atom 1.0 requires "id","title", "link", "author", "updated" elements.

Now, suppose we have a DB table called 'article' with fields 'title', 'url' and 'description' and 'content' fields. We would be making a simple SELECT query, then iterate though the rows and create the final XML as displayed in the PHP program below ::

<?php
// Database Stuffs
$con = mysql_connect("localhost","root","");
mysql_select_db("test");
$sql = "Select title, url, description from article";
$res = mysql_query($sql);

$xml_data = "";

// MAIN LOOP starts
while( $row = mysql_fetch_array($res))
{
  $xml_data .= "<title>". htmlentities($row['title']) ."</title>";
  $xml_data .= "<link>". htmlentities($row['url']) ."</link>";
  $xml_data .= "<description>". htmlentities($row['description']) ."</description>";
}

// Set the output document type through header() function
header("Content-Type: application/rss+xml; charset=utf-8");

// Next, GENERATE the RSS Content
echo '<?xml version="1.0" encoding="utf-8"?>';
echo '<rss version="2.0">';
echo '<channel>';
echo '<title> All Article Listings</title>';
echo '<link>http://www.example.org/aticle-listing-rss.php</link>';
echo '<description>Get Listing of all Articles</description>';
echo '<lastBuildDate>' . date('d M Y h:i:s ') . '+0000' . '</lastBuildDate>';
echo '<language>en</language>';

// Render the DB content
echo $xml_data;

// Concluding Tags
echo '</channel>';
echo '</rss>';
?>


The above code is very simple and easy to understand. However some output characters like single quote or ampersand can cause error. That's why we have used htmlentities() function to convert them to HTML compatible. After we create an RSS feed this way, we may get it checked by validator.w3.org. The output on firefox is shown below ::



If we want to include any article images in the output we can do it two ways :

$xml_data .= "<description>". htmlentities("<a href='". $row['link'] ."'><img src='". $row['image'] ."'></a>") ."</description>";

We created the <img> tag enclosed in an anchor tag to linkify the image. We used htmlentities() function to make these data not available for XML parsing. Characters like "<" and "&" are illegal in XML elements. htmlentities() function would convert <img> to "&lt;img&gt;" which then would not be parsed as XML node. But browser can still build the <img> tag and show the corresponding image on screen in the output.

Similar effect we can achieve through using "CDATA". Check the code below.

$xml_data .= "<description>"  . "<![CDATA[<a href='". $row['link'] ."'><img src='". $row['image'] ."' ></a>]]>" . "</description>";

A CDATA section within XML document starts with "<![CDATA[" and ends with "]]>" and hence it can not contain the string "]]>". Nested CDATA section are also not allowed. Texts like Javascript code should be placed inside CDATA section in XML document.

Download: Fast, Fun, Awesome

Tuesday, May 21, 2013

Fun using css "background-position"


Last week I had checked a beautiful demo of a moving background here and I decided to shell out my own version. Check the image below to learn what I was upto.




The above graphic was done by modifying the background picture position of a DIV using Javascript.

It has four buttons at the bottom, if we click on the "<" button, the digits seem to flow from right to left; by clicking on the '^' button, the digits seem to flow from bottom to top etc. How the whole stuff actually works is described below.

a. First we create an image of digits. Example image is given here..



b. Second, we create a PNG image where the text "PHP" section is totally transparent. Example image is given here..In the picture below, some part is transparent, hence nothing is seen on browser. 


c. We take a DIV with same hight and width as of the PNG image mentioned in step (b) above.
d. We set the background image of the above DIV to the digits image we created in step (a)
e. Now if we change the background-position of the background image of the DIV in a constant manner, the above animation can be achieved.

We set the background image of the DIV through CSS, but we change the "background-position" through Javascript as shown below.

document.getElementById("scrollDiv").style.backgroundPosition = '10px 13px';

The value '10px 13px' defines x-position and y-position of the image. If we increase constantly the y-position from 13px, it would cross the height of the image and hence the image would be gone away and the animated effect would stop. That's why we use "repeat" while setting the background image for the DIV. This would repeat the background image even when we cross the image height/width limit. However, we have put a check in our JS logic that when during scrolling the background image, if any x-position or y-position values are crossing their limit, they are reset to 0.

The Javascript works the following way ::
a. When a button is clicked, we call use-defined scroll() function with a parameter denoting the direction.
b. scroll() function sets a timer so that scr_oll() function is called every 50 milliseconds.
c. The scr_oll() also takes the direction value as a parameter. This function reads the existing background-position style attribute (initially '0px 0px' or '0% 0%') from the DIV. It then clears the 'px' or '%' characters from that value, extracts correct x-pos and y-pos values, then does some maths to set a new value to that background-position style attribute of the DIV. We also check if the x-pos/y-pos values remain within range;

Check the implementation below.

<html>
<head>
<script>
var max_bottom = 300; // Image height of digits.jpg
var max_right  = 599; // Image width of digits.jpg
var timer = '';       // For timer

function scroll(dir)
{
  // Clear any Old Interval if exists
  clearInterval( timer );
  // Set new Interval
  timer = setInterval( function () { scr_oll(dir); }, 50 );
}

// Main function which scrolls the background image
function scr_oll(dir )
{

 // GEt existing background-position
 var backp_css = document.getElementById("scrollDiv").style.backgroundPosition;

 // Remove spl chars
 backp_css = backp_css.replace(/%/g,'');
 backp_css = backp_css.replace(/px/g,'');

 // Split to get xpos and ypos values
 var arr = backp_css.split(" ");

 // Scrolling from top to bottom
 if(dir == 1)
 {
   // For top-to-bottom scroll, we would
   // incerase the ypos value by 1
   var ypos = parseInt(arr[1]) + 1;
  
   // If crossing the maximum, reset
   if( ypos > max_bottom ) ypos = 0;
  
   // Build the final CSS string
   var css_str = arr[0] + 'px ' + ypos + 'px';
 }

 // Scrolling from bottom to top
 if(dir == 3)
 {
   // For bottom-to-top scroll, we would
   // decerase the ypos value by 1
   var ypos = parseInt(arr[1]) - 1;
  
   // If crossing the minimum low, reset
   if( ypos < 0 ) ypos = max_bottom;
  
   // Build the final CSS string
   var css_str = arr[0] + 'px ' + ypos + 'px';
 }

 // Scrolling from right to left
 if(dir == 2)
 {
   // For right-to-left scroll, we would
   // decerase the xpos value by 1
   var xpos = parseInt(arr[0]) - 1;
  
   // If crossing the minimum low, reset
   if( xpos < 0 ) xpos = max_right;
  
   // Build the final CSS string
   var css_str = xpos + 'px ' + arr[1] + 'px';
 }

 // Scrolling from left to right
 if(dir == 4)
 {
   // For left-to-right scroll, we would
   // incerase the xpos value by 1
   var xpos = parseInt(arr[0]) + 1;
  
   // If crossing the minimum low, reset
   if( xpos > max_right ) xpos = 0;
  
   // Build the final CSS string
   var css_str = xpos + 'px ' + arr[1] + 'px';
 }

 // Set new background-position
 document.getElementById("scrollDiv").style.backgroundPosition = css_str;
}
</script>
</head>

<body>



<!-- We set the background Image to the DIV -->
<div id='scrollDiv' style="background:url('digits.jpg');height:250px;width:300px;border:0px solid tomato">
 <img src='php.png' style='display:block'>
</div>

<!-- Direction Buttons -->
<input type='button' value='<' title='Left' onclick='scroll(2)'>
<input type='button' value='>' title='Right' onclick='scroll(4)'>
<input type='button' value='˄' title='Top' onclick='scroll(3)'>
<input type='button' value='˅' title='Bottom' onclick='scroll(1)'>

</body>
</html>


Copy-paste the above code and supply the images used, this would run on all browsers.

The scroll() function clears any previous timer set, by calling clearInterval() function. It is necessary otherwise n number of timer might get created and force the browser to execute all of them at the same interval.

Tuesday, May 14, 2013

File and Folder Iterator in PHP


Problem  : We want to show all files and folders in the curent folder including subdirectories and their content.
Solution : We would be solving this issue using 3 methods as listed below.

a. Using Directories extension
b. Glob method
c. RecursiveDirectoryIterator method

a. The "Directory" extension consists of various useful functions like opendir(), readdir(), closedir(), scandir() etc. Let's use them.

We have a directory stucture as shown in the picture. We would be traversing through each folder recursively and get their respective contents and show them on screen.



Before we fully develop the full solution, here let's write a small program for showing content of current folder. Check the code below.

<?php
print_r( scandir("dir1",0) );
?>


Scandir simply shows all files and folder listings inside the specified path. The output is ..

Array
(
    [0] => .
    [1] => ..
    [2] => 1a.txt
    [3] => 1b.txt
    [4] => dir2
)

The output quite matches the output of DOS "dir" command where single dot "." means current folder and two dots ".." refer to parent folder. The second argument is given for sorting order.. 0 is for ascending order while 1 is for descending order. The folder "dir2" resides inside "dir1" folder and we can get inside "dir2" by implementing one recursive algorithm as shown below...

<?php
// Define a folder to scan
$root_folder = "dir1";

// Call the function for folder browsing
browse_folder( $root_folder );

// Function Definition
function browse_folder( $root_folder )
{
  // Scan the specified path
  $tree = scandir( $root_folder ,  0 );

  // Print Current folder Tree
  echo "<br> Showing content of $root_folder ::<br>";
  print_r($tree);

  // Check if any subfolder exists
  // Ignoring 0th and 1st index
  for($i=2;$i<count($tree);$i++)
  {
    // Check each item using is_dir() for sub-folder checking
    if( is_dir( $root_folder . "/" . $tree[$i] ) )
    {
       // Get into that sub-folder and show content
       // Notice, that this is a recursive call
       browse_folder( $root_folder . "/" . $tree[$i] );
    }
  }

}
?>


The above code traverses all subfolders of specified path and displays all contents inside. If any subfolder is found, then that folder is also browsed and its contents are displayed. We use a recursive call here. All the folders' real path has to be provided to the browse_folder function. That's why we had to use a "/" in the function call ::

browse_folder( $root_folder . "/" . $tree[$i] );

which actually builds the corect path to any subfolder found with respect to the current working directory which in my case is "htdocs". To get your current working directory, write this:

<?php
echo getcwd();
// In my case, it shows C:\xampp\htdocs

// change the current folder to something else
chdir("dir1/dir2");

echo getcwd();
// In my case, it shows C:\xampp\htdocs\dir1\dir2
?>


Another function in Diectories extension is "dir()" which opens a directory and then through read() method we iterate through each item inside.

<?php
// Define a folder to scan
$root_folder = "dir1";

// Open a directory
$fp = dir( $root_folder );

// List files in it
while ( ($file = $fp->read()) !== false)
{
  echo "File: " . $file . "";
  echo is_dir( $root_folder . "/" . $file) ? "[dir]" : "[file]" ;
  echo "<br/>";
}

// Close the directory
$fp->close();
?>


The dir() method creates an instance of Directory class with two member variable namely "path" and "handle". The above code would generate a list of all file and folders inside the directory specified.

Let's solve this folder browsing problem once again using opendir() and readdir() methods. Check the code below.

<?php
// Define a folder to scan
$root_folder = "dir1";

// Call the function for folder browsing
browse_folder( $root_folder );

// Function Definition
function browse_folder( $root_folder )
{
   // Check if it a dir
   if( is_dir( $root_folder ) )
   {
     // TRY to open a handle for the dir
     $fp = opendir($root_folder);
    
     // dir opening problem may occur due to file
     // pemission or other file system error
     if($fp !== false )
     {
        echo "<br> Showing content of [$root_folder] ....";
       
        // Read next entry from directory handle
        // in the order in which they are stored
        // in the fileSystem
       while ( ($file = readdir($fp))  !== false)
       {
         // File or Folder with Relative Path

         $fi_le = $root_folder . "/" . $file ;

         // Display file/folder name etc
         echo "<br> filename: [$file], filetype: [" . filetype(
$fi_le ) . "]" ;
   
         // If it is a Sub folder, then again get inside it
        if( $file!= "."  && $file!=".." )
        {
         if( filetype(
$fi_le ) == "dir" )
         {
           // Make the recursive call
           browse_folder(
$fi_le );
         }
        }
       } // While closes
      } // If closes

     // Close the directory Handle
     closedir($fp);
   }
}
?>


The above code would beautifully display all your folder contents. Check the output below :



Couple of points to be noted here ..
i. opendir() should be accompanied by a respective closedir() method which closes the directory handle opened by opendir()
ii. We use filetype() function which returns "dir"/"file" if the supplied item is a "directory"/"file" respectively.
iii. We ignored the "." and ".." folders
iv. readdir() function reads next item within the specified directory and retuns "FALSE" if anything goes wrong. In my case, files are displayed ahead of folders which is why I could avoid the pain in displaying the contents. Say, if readdir() reads a folder content as shown below...

file1.txt [file]
file2.txt [file]
folder1   [dir]
file3.txt [file]
folder2   [dir]
file4.txt [file]


In this case the above code would first print "file1.txt" and "file2.txt" and then it recursively calls the browse_folder() function to show contents of "folder1", then again "file3.txt" would be displayed and next contents of "folder2" would be displayed and so on... This way the output may become totally unordered. This problem may arise because we are using a single loop for displaying items and browsing sub-folders. However this problem can always be overcome by the following logic.. Just using two separate loops for displaying and subfolder-browsing.

i) Display all contents of current folder using readdir() in a loop
ii) Rewind the directory handle by using rewinddir($fp) statement
iii) Again start a loop using readdir() to see if any folder is sub-folder. If a sub-folder is found, then call the browse_folder() method

Glob method is discussed in article Using Glob in PHP

DirectoryIterator methods are discussed in article DirectoryIterator in PHP

HTML Select element manipulation using jQuery - II

We have already discussed a few points on Select element manipulation with jQuery in my previous article, here we would be discussing few more points.

Check the HTML below, it contains the select element which we would be working upon.

<select id='selectBox1' name='select' size='10' multiple='multiple'>
 <option value='apr'> Aprilia </option>
 <option value='duc'> Ducati </option>
 <option value='hro'> Hero </option>
 <option value='hnd'> Honda </option>
 <option value='hyo'> Hyosung </option>
 <option value='kwk'> Kawasaki </option>
 <option value='suz'> Suzuki </option>   
 <option value='yam'> Yamaha </option>
</select>


6. Remove a single option from the list

If we want to remove the " Aprilia " from the list, we can take following steps...

i. Iterate through the loop options
ii. If option's text matches with text, then we remove it.

Check the jquery implementation..

<script>
// Use each() function
j("$selectBox1 option").each(

// Callback function for each()
function()
{
 
  /// Option Text is being matched here
  if( j(this).text() == " Aprilia " )
   {
      // Remove the Option
      j( this ).remove();

      // Break;  -- WE can't write a BREAK here
      // Hence each() function will iterate till
      // the last option in th list even if
      // an option is found and deleted.
   }

} // CallBack ends

); // each() ends
</script>


However, we can use a different selector to select an option directly and remove it.

<script>
// Remove the second child from the top
j("#selectBox1 option:nth-child(2)").remove();

// Get total count of all the options
alert ( j("#selectBox1 option").length );
</script>


As discussed earlier, children indexes start from 1 for nth-child selector.

Suppose, we need to delete option " Suzuki " immediately before the last option " Yamaha ". We can use another approach other than the option text matching method discussed above. Check the code below.

<script>
// Get total count
var l = j("#selectBox1 option").length;

// We need to remove the item immediately before index l
l = l-1;

// Build the selector
var str = "#selectBox1 option:nth-child(" + l + ")" ;

// Now remove the item
j(str).remove();

</script>


For a long list with 20000/30000 options, we can surely use the above method.

Here is another approach which is much easier in case we want to delete items/options closer to last item or first item.

<script>
// Get the previous item to the last item
j("#selectBox1 option:last").prev().remove();

// Or we can refer to as many previous items as we wish
j("#selectBox1 option:last").prev().prev().prev().prev().remove();
</script>


7. Remove all/multiple options from the list
To remove all options from a listbox, we can write the following statement...

<script>
// Remove all options at one go
j("#selectBox1 option").empty();
</script>


But the above statement clears all the option texts, the option elements still exist with their respective values. This happens because we have used a wrong selector. "#selectBox1 option" means we referring to all options under "#selectBox1" select element and clearing each of them. And as a result, all option elements are cleared off their texts. The right syntax would be :

<script>
// Remove all options at one go
j("#selectBox1").empty();
</script>


To remove all selected options from a list box, we need to write the following jQuery...

<script>
// Remove all Selected options at one go
j("#selectBox1 option:selected").remove();
</script>


The selector "option:selected" refers to all options in the list which are selected. Another longer approach..

<script>
j("#selectBox1 option:selected").each( function(){ j(this).remove();} );
</script>


Here, we are iterating each selected item with each function... and then delete item.

See, how easier it is to do with jQuery. It would have been much difficult to achieve the same thing as discussed in article HTML Select element manipulation using Javascript - II.

8. Edit any option at any position within the list

Suppose, we want to edit the first option " Aprilia " and change it to "BMW", we can use the jQuery text() and val() functions for achieving this.

<script>
j("#selectBox1 option:first").text(" BMW ").val("bmw");
</script>

The selector "option:first" refes to the first item in the list, the text() function changes its content text while the val() function changes its value. More complex statment can be built like ..

<script>


// refer to 3rd option, then 2 prev() call would
// get us to the fist option itself.
j("#selectBox1 option:nth-child(3)").prev().prev().text(" BMW ").val("bmw");
 

</script>

9. Create a copy of the select element and append it to the body

With jQuery, solving complex tasks like this becomes very easier. Check the following code...

<script>
// Create a clone of existing select element
var p = j("#selectBox1").clone();

// Now append it to document body
// document.body is Native JS
j( p ).appendTo( document.body );

// Now try to append again
// j(document.body) is jQuery
// But this does not seem to work
// Same node can not be inserted again
j( p ).appendTo( j(document.body) );

// Workaround ?? Try this ...
j( j(p).clone() ).appendTo( j(document.body) ); // It works

</script>


An node/element, after its creation, can be inserted to the HTML DOM only once. Further insertion statements does not successfully insert new node.

The above code, clones a select element and inserts into HTML DOM but it creates multiple select element with same ID. Hence we must change newly created element's ID to something else as shown in the example below.

<script>
// Create a clone of existing select element
var p = j("#selectBox1").clone();

// Now set its ID property
j( p ).attr('id','selectBox2');

// Append to an existing form with ID 'frm'
j( p ).appendTo( j( "#frm" ) );

// Create another ANother
j( j(p).clone().attr("id","selectBox4") ).appendTo( j("#frm") );
</script>


Notice, we are adding the "id" attribute to a cloned node and then appending it to an existing form on the document body.

10. Sorting all options in a Select element

We had to do huge stuffs while achieving this with Javascript. With jQuery, we have to follow similar steps but we would write lesser statements. Check out the code below..

<script>
// Create an array of all option nodes
var p = j("#selectBox1 option");

// Sort the array of nodes according to
// their TEXT content
p.sort(function(a,b) {
    if (a.text > b.text) return 1;
    else if (a.text < b.text) return -1;
    else return 0
})

// Now clear the Select element
j("#selectBox1").empty();

// Re-build all options into the Select element
j("#selectBox1").append( p );

</script>


Check the previous part Here.

For having filtering options on a select element, visit this. It has some really great example of a jQuery filtering plugin usage.


11. Selecting/Unselecting all options in a Select element

This is achievable when it is a Multi-select Selectbox element. To do this, we need to assign selected='selected' to each option within the select element. Check the code below.

// Select All Options
jQuery("#selectBox1 option").each(
   function()
   {
     // Add Attribute
     jQuery(this).attr('selected','selected');
   });

// Un-Select All Options
jQuery("#selectBox1 option").each(
   function()
   {
     // Add Attribute
     jQuery(this).removeAttr('selected');
   });