0

Working with jQuery and CakePHP

Recently I’m working with CakePHP and SQLite to develop a gallery for a client. This is going to be my first CakePHP app.

While I’m working on the admin section, I wanted to allow the client to see the image once the image filename field is out of focused so that he could see if it’s the correct image.

The only JS library included with CakePHP is Prototype. Fortunately, the latest version of CakePHP (1.3.11 as of right now) allows us to include with other JS library. I included jQuery with the help of Js helper:

var $helpers = array("Js"=>array("Jquery"));

The above code is included with the whatever controller(s) you want to use this helper. In my case is galleries_controller.php and images_controller.php.

Then I just need to add the following code into the corresponding views, in my case is some of the admin views (admin_edit.ctp, and admin_add.ctp):

echo $this->Js->set("imageLoc", $this->Html->image("0"));

echo $this->Js->get("#GalleryCover")->event("blur", "$('#cover').html(window.beta.imageLoc.substring(0, window.beta.imageLoc.length-12) + 'images/' + $('#GalleryPath').val() + '/thumb/' + $(this).val() + '" />');");

Note that I used image object in the Html helper to generate a dummy img tag so that I could precisely get the image folder location in the webroot folder. Then I used set object in the Js helper to transfer this generated PHP value to Javascript variable “imageLoc”. The second line is self-explanatory if you know jQuery. Here is the documentation in the CakePHP Cookbook for you to review.

In the jQuery code section of the second line, I used the substring function to remove the last 12 characters in the img tag (0″ alt=”" />). And used the html function to include the generated code into the “cover” div. Every time the “GalleryCover” field is blurred out of focus, the image inside the “cover” div would change to the corresponding images.

If you need more information on how to use CakePHP generated Javascript variables, please refer to the second article in the reference section.

Do you have any other tips on how to incorporate jQuery into CakePHP? Please share them in the comment below.

Reference

0

Remove AIO SEO related Columns with Greasemonkey and jQuery in WordPress

1

A Small Fancybox Tip – Show scrollbar when viewing Large Images

onStart callback function

Intro

I use Fancybox jQuery plugin to view large/original size of images. However, its default settings don’t setup to view the large size images. It auto resizes based on the browser window size instead. According to the documentation, the options “autoScale” and “scrolling” disables the automatic scaling and enables the scrollbar to be visible respectively. However, I couldn’t figure out the scrolling option since the horizontal scrollbar is missing when viewing a large image that is bigger than the browser width. After looked into the code generated by Fancybox, I noticed that the scrolling option is applied to other than the body element, which is what I want the scrollbars to be at (edges of the browser window). So I used onStart option to write a callback function that set the overflow property for the body element to be visible.

The Code

$("element").fancybox({
 transitionIn: "elastic",
 transitionOut: "elastic",
 autoScale: false,
 onStart: function() {
  $("body").css({overflow:"visible"});
 }
});

Below is the difference between use the scrolling option and use the onStart callback function:

Scrolling

Scrolling Option

onStart callback function

onStart Callback Function

Questions

All of the above options are explained in the Fancybox document page. If you still have questions, feel free to ask them below.

0

Selectively Include jQuery Plugins

jQuery

Introduction

I’m often using jQuery and a little PHP because of the recent interest in the jQuery animation. Therefore I need lots of jQuery plugins to load in every web page. I need some plugins on each page such as Color plugin for the navigation and IE font-face ClearType fix for adding font-face support to IE, but I don’t need other plugins to load unless there is a page element specifically used with those plugins.

The Code

 // Function to create script element dynamically
function createScript(src) {
 var script = document.createElement("script");
 script.src = "scripts/" + src + ".js";
 script.type= "text/javascript";
 $("body").append(script);
}
$(window).load(function() {
  // Load the custom fonts in IE
 $("body").ieffembedfix();
  // Top Navigation Menu Animation
 $("#horiNav a").hover(function() {
  if ($(this).attr("id") != "currentPage") {
   $("#currentPage").stop().animate({backgroundColor:"#FFF", color:"#87CEEB"});
   $(this).stop().animate({backgroundColor:"#A7D4F2", color:"#FFF"});
  }
 }, function() {
  if ($(this).attr("id") != "currentPage") {
   $(this).stop().animate({backgroundColor:"#FFF", color:"#87CEEB"});
   $("#currentPage").stop().animate({backgroundColor:"#A7D4F2", color: "#FFF"});
  }
 });
 if ($("#slideshow").length != 0) {
   // Load the Cycle plugin dynamically
  createScript("jquery.cycle.all.latest");
   // Cycle through the slideshow on the home page
  $("#slideshow").cycle({
   fx: "fade",
   timeout:"3000",
   pager:"#SSnav"
  })
   // Stop the slideshow once it is clicked
  .bind("click", function() {
   $(this).cycle("toggle");
  });
 }
});

Explanation

Here I defined a function that creates a script element before the end of body. The function basically used raw Javascript code to create script element and a line of jQuery code to append the new element to the body.

I used $(window).load instead of $(document).ready method to execute the jQuery code after the page is loaded. I then demonstrated the code for the font-face support for IE and the navigation color animation.

In order to selectively include jQuery plugins, check the existence of the element that requires to use those plugins first. I used if statement to check the length of the element. Include the jQuery plugins if the number of the specified element is at least one. Then execute rest of the code within the if statement. The screenshot below shows Firebug that the page has successfully loaded the required plugin.

Loaded required jQuery plugin successfully

Loaded required jQuery plugin successfully

Head over to wcf.robbychen.com to see it in action. Make sure to open Firebug when visiting the site to see which jQuery plugins are loaded. Right now only the homepage and Who We Are page use additional jQuery plugins.

Questions

If you have any question about the above code, feel free to post them in the comments below.

0

Final Revision for Scrolling Animation Code, Maybe

scrollAnime

Introduction

After I revised the scrolling animation jQuery code yesterday, I was going to rewrite it using Mootools. However, I noticed that this code was doing two unnecessary actions. The first one is the removing of the first set of images, and another one is the appending of new sets of images. Several minutes after my eyes watched the scrollbar animate back and forth, I revised the code to the following.

The Code


if ($("#whoWeAreImages").length != 0) {
  // Scroll Animation for the images in the Who We Are page
 var $whoWeAreImages = $("#whoWeAreImages"),
 $wwaLink = $whoWeAreImages.find("a"),
 $wwaImg = $whoWeAreImages.find("img"),
 scrollWidth = $whoWeAreImages.attr("scrollWidth");
  // Do the following once the page is loaded
 $whoWeAreImages.css({overflow:"hidden"})    // Hide the images scrollbar
 .scrollLeft(0)    // Make sure the scrollbar is at the beginning when the page is reloaded
 .append($(this).html()) // Add one more set of images
  // Begin the animation
 .autoscroll({
  direction: 0,
  step: 50,
  onEvaluate: function() {
    // Click action for the images in the Who We Are page
   $wwaLink.fancybox({
    transitionIn: "elastic",
    transitionOut: "elastic"
   })
    // Scroll to the beginning once it scrolls to the beginning of the second set of images
   if ($(this).scrollLeft() >= scrollWidth) {
    $(this).autoscroll("pause");
    $(this).attr("scrollLeft", "0");
    $(this).autoscroll("resume");
   }
  }
 })
 .autoscroll("addpausesource", $wwaImg);
}

Explanation

In the above code, I removed the remove() action and added the append action at the beginning of the loop. It means that it will only has two sets of images available instead of an infinite loop that remove and append continuously to limit two loops which has slower performance.

After this revision, the animation lag still exists. This is probably the final revision of the code before I rewrite it using Mootools because I might discover some techniques during the rewriting of this code.

1

Auto Scroll Images jQuery Animation

scrollAnime

Update (12/14/2010): I wrote the revised code for better performance.

Introduction

Based on the last past, I wrote a jQuery snippets to automatically scroll through the images horizontally. I used scrollLeft and scrollWidth attributes to achieve this animation. And if the scrollbar scrolled to the end of the element, it will append the original content in the element to the end of the element in order to loop through the images. Take a look at the source code below to see what I mean. Note that the HTML code is the same as last post.

The Source Code

 // Scroll Animation for the images
var div = $("#div");
 // Do the following once the page is loaded
div.css({overflow:"hidden"});    // Hide the images scrollbar
div.attr("scrollLeft",0);    // Make sure the scrollbar is at the beginning
 // Begin the animation
var scrollAnime = function() {
 div.animate({"scrollLeft":"+=20"}, 1000, "linear");
  // Append the same images to the end of the last image if it finished scrolling to loop through the animation
 if (div.attr("scrollLeft") >= div.attr("scrollWidth") - div.width() - 10) {
  div.append(div.html());
 }
  // Click action for the images
 $("#div a").fancybox({
  transitionIn: "elastic",
  transitionOut: "elastic"
  });
 }
 var beginAnime = setInterval(scrollAnime, 1000);

  // Stop the animation in hover state
 div.hover(function() {
  clearInterval(beginAnime);
 }, function() {
  beginAnime = setInterval(scrollAnime, 1000);
 });

CSS recommendation: (Optional if you don’t want the animation to show where to end/start the new loop of the images)

#div .lastImage {
 border-right:1px solid #000;
 padding-right:1em;
 margin-right: 1em;
}

Explanation

Firstly, as you can see in the source code, I use Fancybox jQuery plugin to view enlarged images. I put this piece of code inside the setInterval function together with the rest of the code so that it can recognize the new images which are generated inside the function. I also set the scrollLeft to 0 when the document is loaded to ensure that the scrollbar resets to the left when the page is refreshed. The default value for the third parameter of the animate function is swing. In order to make the ScrollLeft animation more smooth, I changed it to linear since there are only these two values available when used with jQuery, according to the API documentation. Other section in the source code above is explained in the comments after each line. One thing to note is that I found the usage for  the third parameter for the animate function  in the source code of image board jQuery plugin which is similar to my code above, except it will not loop through the images continuously, instead it goes back to the first image once it passed the last image.

You can see a demo of the above code at wcf.robbychen.com.

Since I don’t know how to write a jQuery plugin yet, I’m sure that there are similar plugins out there. If you find one, please share it in the comments section below.

4

Enable Backspace in Chromium

Since I discovered that Google doesn’t add the backspace support to its Chrome browser to navigate between web pages history, I always tried to find a way to add this shortcut key support to Chromium. I don’t like to press two or more keys combo (in this case, alt + left) just to go back one page, especially in the low-light condition when I cannot clearly see the keyboard.

Finally, with the help of an Ubuntu forum I found a Chrome extension called Backspace As Back/Forward for Linux. Once you installed this extension, the backspace key icon () would appear at the end of the URL address bar along with other extensions when the web pages history is available. Note that you need to refresh the existing opened web pages in order to activate the extension.

The only disadvantage I’ve found with this extension is that the page needs to be fully loaded in order to activate the backspace key. I think this is the nature of Chrome extension since the Chrome extensions are JavaScript / AJAX based.

0

More About CA272 (Pro Website Development) Final Project

CA272 Final Project LogoSince I mentioned the CA272 final project a little in the last post, I think it’s best to talk more about this topic.

I took CA272 class in the Spring of 2009. It is known as Professional Website Development. Actually to me, this is not a professional class. Instead, it is a very basic class: it doesn’t include sever-side script languages nor JavaScript, just basic HTML4. At that time however, I didn’t know jQuery and PHP until the very end of the semester.

As you can see through the source code of the Final Project page, all of the AJAX and JavaScript functions were created by myself. Because I discovered jQuery during the last week of final project submission, I hurriedly added some animated transitions to the pages using jQuery without the deep understanding of jQuery. Therefore, the animation looks a little incomplete.

The presentation below explains the most of features on the site:

Note that because I don’t have my own website at the time, I copied all the final project files to a free hosting. Therefore, the URL at the end of the video is not valid anymore, use http://robbychen.com/ca272/final/ instead.

0

More Than One Month Usage of Chromium

I used Google Chrome on Ubuntu 9.10 and switched to Chromium on Ubuntu 10.04. Apart from being open source, I can’t tell any difference between Google Chrome and Chromium. During the switch process from Firefox to Chromium in the web development environment, I didn’t have any problems since I mostly used server-side script languages. Recently I have been interested in MooTools JavaScript Framework and followed its guide to test the code in Chromium. All went well until I test the class code. It seems that Chromium does not support document.write() JavaScript function very well. It worked in Firefox after my test with Chromium failed. I’m not familiar with Chromium’s JavaScript engine, but in my experience, Chrome has similar problem since the early build of Chrome 1. Long time ago, I used Chrome 1 alpha as my default web development environment in Windows. It disappointed me that Chrome didn’t have a complete JavaScript engine yet. It is ashamed that Google still has little bit of problems with its browser’s JavaScript engine as the market share of Chrome continues to go up. As a user, my overall usage experience of Chromium is good. However, Chromium doesn’t suited for my web development yet.

0

HTML Template PHP class

This is my first fully-written PHP class to ease my HTML page creation process by pre-set the DOCTYPE and other required tags in a normal HTML page. The class is inspired by this article where it talks about wp_header and wp_footer of WordPress. I thought that this is a great exercise to increase my OOP (Object-Oriented Programming) skill. Therefore I wrote the following code based on my creation habit for HTML pages:

<?php
    class template {
        public $title;
        public $style;

        function header($headerContent="") {
            echo "<!doctype html>n";
            echo "<html>n";
            echo "<head>n";
            echo "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />";
            echo "<title>";
            echo $this->title;
            echo "</title>n";
            if (isset($this->style) || !empty($this->style)) {
                echo "<link href='{$this->style}' rel='stylesheet' type='text/css' />n";
            }
                // Output additional header content if available
            if (function_exists($headerContent)) {
                $headerContent();
            }
            echo "</head>n";
        }

        function body($bodyContent="") {
            echo "<body>n";
                // Output body content
            if (function_exists($bodyContent)) {
                $bodyContent();
            }
        }

        function script($script='') {
            if (strstr($script, ".js") || strstr($script, "://")) {
                echo "<script type='text/javascript' src='{$script}'></script>n";
            }
            else {
                if (strstr($script, "()")) {
                    $function = str_replace("()", "", $script);
                    if (function_exists($function)) {
                        $function();
                    }
                }
                else {
                    echo "<script type='text/javascript'>n";
                    echo $script;
                    echo "</script>n";
                }
            }
        }

        function footer($footerContent="") {
            if (function_exists($footerContent)) {
                $footerContent();
            }
            echo "</body>n";
            echo "</html>n";
        }
    }
?>

The header, body, and footer methods include an optional string variable. As you can see in the code above, this variable needs to be a function name. The function name in these three methods doesn’t require parentheses. However, the function name needs to have parentheses in the script method. The script method is different from the above three methods as it can be reused in the same HTML page. For example, the following is a simple page with the class applied:

<?php
    $ca282 = new template();
    $ca282->title = "Robby Chen CA 282";
    $ca282->style = "styles/global.css";
    $ca282->header("headerContent");
    $ca282->body("bodyContent");
    $ca282->script("http://www.google.com/jsapi");
    $ca282->script("google.load('jquery','1')");
    $ca282->script("jquery()");
    $ca282->footer();
?>

Notice that the script method has three formats in the above example, external JS, on-line code, and a function. I didn’t pre-set the script tag between function because I need the syntax highlighting and auto-completion features in NetBeans. The following is my jquery() function in case you don’t know how to activate these two features within a PHP function:

<?php
    function jquery() {
?>
<script type="text/javascript">
    $(document).ready(function() {
        $("#logo").html("Logo");
    });
</script>
<?php
    }
?>

Basically, the JavaScript code is outside the php tag but inside the PHP function. This way the script content will only appear after the jquery function is called.

You can download the class file here.

<?php
class template {
public $title;
public $style;

function header($headerContent=”") {
echo “<!doctype html>n”;
echo “<html>n”;
echo “<head>n”;
echo “<meta http-equiv=’Content-Type’ content=’text/html; charset=utf-8′ />”;
echo “<title>”;
echo $this->title;
echo “</title>n”;
if (isset($this->style) || !empty($this->style)) {
echo “<link href=’{$this->style}’ rel=’stylesheet’ type=’text/css’ />n”;
}
// Output additional header content if available
if (function_exists($headerContent)) {
$headerContent();
}
echo “</head>n”;
}

function body($bodyContent=”") {
echo “<body>n”;
// Output body content
if (function_exists($bodyContent)) {
$bodyContent();
}
}

function script($script=”) {
if (strstr($script, “.js”) || strstr($script, “://”)) {
echo “<script type=’text/javascript’ src=’{$script}’></script>n”;
}
else {
if (strstr($script, “()”)) {
$function = str_replace(“()”, “”, $script);
if (function_exists($function)) {
$function();
}
}
else {
echo “<script type=’text/javascript’>n”;
echo $script;
echo “</script>n”;
}
}
}

function footer($footerContent=”") {
if (function_exists($footerContent)) {
$footerContent();
}
echo “</body>n”;
echo “</html>n”;
}
}
?>