Posts tagged with jQuery

Avatar-eric-london
Created by Eric.London on 2011-06-16
Tags:
New Comment
 
Please note: the content on this page orginates from ericlondon.com.
In this article, I'll share some code that I use to gray out the screen during AJAX calls to prevent users from clicking on anything, and displays a visual cue to the user that their click request is still being processed.

In the following code, I created a hook_menu() implementation and 2 page callbacks; one to show a clickable link and the other to process the AJAX request.

<?php
/**
 * Implements hook_menu()
 */
function helper_menu() {

  $items = array();

  // define the page callback to show the clickable link  
  $items['shadow-test'] = array(
    'title' => t('Shadow Test'),
    'page callback' => '_helper_page_callback_shadow_test',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );
  
  // define the page callback to process the AJAX request
  $items['shadow-test-ajax'] = array(
    'title' => t('Shadow Test Ajax'),
    'page callback' => '_helper_page_callback_shadow_test_ajax',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );
  
  return $items;

}

/**
 * Implements the page callback to show the clickable link
 */
function _helper_page_callback_shadow_test() {

  // include module css
  drupal_add_css(drupal_get_path('module', 'helper') .'/helper.css');

  // include module javascript
  drupal_add_js(drupal_get_path('module', 'helper') .'/helper.js');

  // generate shadow html
  $shadow_html = "<div id='shadow' style='background: url(" . '"' . base_path() . drupal_get_path('module', 'helper') .'/shadow.png' . '"' . ")'></div>";

  // define javascript variables to be passed to the DOM
  $js_vars = array(
    'helper' => array(
      'ajax_path' => base_path() . 'shadow-test-ajax',
      'shadow_html' => $shadow_html,
    ),
  );

  // pass variables to javascript
  drupal_add_js($js_vars, 'setting');

  // create a variable for page output
  $output = "";
  
  // create a clickable link
  // NOT: this link will be overwritten via jQuery
  $output .= l(
    t('Click Me'),
    $_REQUEST['q'],
    array(
      'attributes' => array(
        'class' => 'ajax_clickable',
      ),
    )
  );
  
  // return page output
  return $output;

}

/**
 * Implements page callback to process the AJAX request
 */
function _helper_page_callback_shadow_test_ajax() {

  // wait 2 seconds
  // NOTE: this line is just used to demo the "shadow" effect
  sleep(3);
  
  // return a JSON value
  $ret = new StdClass();
  $ret->status = true;
  print drupal_json($ret);

  die;

}
?>


After flushing my menu cache, and browsing to the first page callback, I see the following:

Shadow Off

I added some CSS to my module's CSS include file (helper.css), to help position the "shadow" full screen:


#shadow {
  z-index: 1000;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: none;
}


I created a 50% black transparent PNG image in PhotoShop:

50% black image

I added some jQuery to my module's javascript include file (helper.js), to add the click event to the link, and two functions to hide and show the shadow.



Drupal.behaviors.helper = function(context) {

  // find the link with the matching class, and add a click event
  $('.ajax_clickable').click(function(){
    
    // show shadow
    $(this).show_shadow();

    // make ajax call    
    $.getJSON(
      Drupal.settings.helper.ajax_path,
      function(data) {
        
        // when the ajax call is done, hide the shadow
        $(this).hide_shadow();
        
      }
    );

    // prevent the a tag from actually going anywhere
    return false;
  
  });
  
}

;(function($) {

  // defines the function to show the shadow
  $.fn.show_shadow = function() {
  
    // ensure the shadow does not already exist
    if ($('body #shadow').length == 0) {
      
      // add shadow html, and fade it in
      $('body').append(Drupal.settings.helper.shadow_html).find('#shadow').fadeIn();
          
    }
  
  }

  // defines the function to hide the shadow
  $.fn.hide_shadow = function() {
  
    // fade it out, and then remove it from the dom
    $('#shadow').fadeOut('slow', function() {
      $(this).remove();
    });
  
  }
  
})(jQuery);


Now, when I click on the link the page fades to black and the user cannot click on anything. After the 3 second delay (defined in the AJAX callback), the black shadow fades away.

Shadow On
Avatar-eric-london
Created by Eric.London on 2010-10-24
Tags:
New Comment
 
Please note: the content on this page orginates from ericlondon.com.
In this tutorial I'll explain how to setup your Drupal site to be mobile friendly. Before you begin, it's helpful to consider the following: 1) which mobile devices to support; 2) using a different theme for mobile; 3) which hostnames will be used; 4) multi-site configuration options; and 5) any site alterations to simplify the mobile experience.

For my site, I decided on the following:
1) iPhones (to start)
2) Use a more clean theme for my mobile site: DevSeed's Singular
3) redirect mobile traffic to a new subdomain (mobile.ericlondon.com)
4) I was using sites/default for my blog, so hosting another hostname on the same filesystem was not an issue
5) I decided to remove some items in my primary navigation, and add some jQuery (accordion effect) to collapse node content on my front page.

I added the new DNS for my subdomain to point to the same IP address of my main site. In a standard Apache vhosts configuration, you can add a ServerAlias directive to ensure the mobile hostname is handled by the main site's vhost. For example:


<VirtualHost *:80>
  ServerName ericlondon.com
  ServerAlias mobile.ericlondon.com
  DocumentRoot /var/www/vhosts/ericlondon.com/httpdocs
</VirtualHost>


I installed and enabled the Singular theme in sites/all/theme/singular.

I added some mobile specific configurations in my settings.php file (sites/default/settings.php):

<?php

/**
 * Mobile Theme Configuration
 */

// define mobile http host
define('MOBILE_HTTP_HOST', 'mobile.ericlondon.com');

// define mobile theme
define('MOBILE_THEME','singular');

// override custom theme for mobile site
if ($_SERVER['HTTP_HOST'] == MOBILE_HTTP_HOST) {
  $GLOBALS['custom_theme'] = MOBILE_THEME;
}

// check for iPhone
$is_iphone = preg_match('/iphone/i', $_SERVER['HTTP_USER_AGENT']);  

// redirect to mobile theme
if ($is_iphone && $_SERVER['HTTP_HOST']!=MOBILE_HTTP_HOST) {
  header('Location: http://' . MOBILE_HTTP_HOST . $_SERVER['REQUEST_URI']);
  die;
}

?>


Now, if someone visits my site using an iPhone, the user would be redirected to my specified mobile address, AND a new mobile theme would be used!

Mobile iPhone

In addition, I decided to make some alterations to my mobile theme to simplify the interface. I created a module and added a hook_preprocess_page() implementation:


<?php
function MYMODULE_preprocess_page(&$vars) {

  // only process page variables if this is the mobile address
  if ($_SERVER['HTTP_HOST'] != MOBILE_HTTP_HOST) {
    return;
  }

  // define mobile javascript
  /*
  NOTE: this jQuery is very specific to my theme, and is just shown as an example.
  I looked into using jquery_ui's accordion library, but it would not work out of the box with the structure of my new mobile theme :(
  In an ideal situation, all jQuery would be put in separate include files
  */
  $js = "
  
    // define node container
    var node_container = '.front #page #content';
      
    // define function to collapse node content
    function collapse_nodes() {      
      $(node_container + ' .node div').hide();
    }
  
    // define function to add click event
    function node_title_add_click() {
      $(node_container + ' .node h2.node-title a').click(function(){
        collapse_nodes();
        $('div', $(this).parent().parent()).show();
        return false;
      });
    }
    
    $(document).ready(function(){

      collapse_nodes();
      node_title_add_click();
      
    });
  ";
  drupal_add_js($js, 'inline');
  
  // rebuild scripts variable
  $vars['scripts'] = drupal_get_js();
  
  // determine a list of hrefs to remove from primary navigation
  $href_remove = array(
    'drupal',
    'tagadelic/chunk/1',
    'recent-posts',
    'rss.xml',
    'logout',
    'contact',
  );
  
  // loop through primary links and remove as necessary
  if (is_array($vars['primary_links'])) {
    foreach ($vars['primary_links'] as $key => $value) {
      if (in_array(strtolower($value['href']), $href_remove)) {
        unset($vars['primary_links'][$key]);
      }
    } 
  }
  
}
?>


By added the above module code and jQuery, I removed some items from my primary navigation and added an accordion-like interface for the front page:

Mobile theme

NOTE: If you're using a Mac, the iPhone Simulator application (which comes with Xcode + iPhone SDK) is a great way to development and test mobile configurations.
Avatar-eric-london
Created by Eric.London on 2010-05-22
Tags:
New Comment
 
Please note: the content on this page orginates from ericlondon.com.
In this tutorial, I'll show a way to pass PHP/Drupal variables to javascript/jquery using drupal_add_js(), and a way you can debug javascript variables using the FireBug console.

I'll start by creating a hook_menu() implementation to establish a page callback:
<?php
function helper_menu() {

  $items = array();
  
  $items['js-vars'] = array(
    'title' => t('Javascript Variables'),
    'description' => t('Javascript Variables'),
    'page callback' => 'helper_page_callback_js_vars',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,    
  );
  
  return $items;

}
?>


Next, I'll define the page callback:
<?php
function helper_page_callback_js_vars() {

  // include module javascript file
  drupal_add_js(drupal_get_path('module','helper') . '/js/helper.js');

  // define variables you'd like to pass to the DOM
  $js_vars = array(
    'js_vars' => array(
      'message' => t('Hello @username', array('@username' => $GLOBALS['user']->name)),
      'an_array' => array(
        'color' => t('red'),
        'name' => t('Eric'),
      ),
    ),
  );
  
  // pass variables to javascript
  drupal_add_js($js_vars, 'setting');
  
  // generate some page output
  return "TEST";

}
?>


And here is the contents of the javascript include file I stuck in my module directory:

$(document).ready(function(){

  // debug variables directly in FireBug
  console.debug(Drupal.settings.js_vars);
  
  // popup mesage passed from Drupal
  alert(Drupal.settings.js_vars.message);
  
});


When viewing this page in a browser, you'll see the following. The javascript popup window is using variables passed directly from a Drupal/PHP array:
javascript popup

The console.debug() javascript method was used to send data directly to the FireBug console. If you open FireBug, you'll see the following:
FireBug Console

If you click on the Object shown, you can drill into the variables further:
FireBug Console





Avatar-eric-london
Created by Eric.London on 2009-09-01
Tags:
New Comment
 
Please note: the content on this page orginates from ericlondon.com.
I recently signed up for Google AdSense and I thought it would be fun to show ads for Internet Explorer users. Of course, you could use this tutorial for more productive purposes. Here is how I integrated this functionality into my theme.

I added 2 regions to THEME.info file:

regions[ad_left] = Ad Left
regions[ad_right] = Ad Right


I then included the regions in my theme by adding some code to my theme's page.tpl.php file:

<?php if ($ad_left): ?>
  <div id='ad_left' class='google_ads'>
    <?php print $ad_left; ?>
  </div>
<?php endif; ?>

<?php if ($ad_right): ?>
  <div id='ad_right' class='google_ads'>
    <?php print $ad_right; ?>
  </div>
<?php endif; ?>


Next, I added some CSS in my style.css theme file to absolutely position the regions in a fixed position:

.google_ads {
  position: absolute;
  bottom: 10px;
  width: 120px;
  height: 600px;
  display: none;	
}

.google_ads .block {
  padding: 0;
  margin: 0;
}

body > .google_ads {
  position: fixed;
}

#ad_left {
  left: 10px;  
}

#ad_right {
  right: 10px; 
}


Now that my regions were setup, I added 2 blocks containing the Google AdSense code and assigned the blocks to my new regions. You'll need to make sure the input filter you choose allows for javascript to be included.

At this point, the ads are included for every browser, but they will not be shown due to the "display: none" property I added to the "google_ads" CSS class. I added a few lines of jQuery in my theme's script.js file to show the regions for IE users:

$(document).ready(function(){
  // per IE ads
  if ($.browser.msie) {
    $('.google_ads').show();	  
  }
});


If you view this page in IE, you'll see my code in action ^_^

My additional thoughts... this code executes the Google AdSense javascript regardless of your browser, but it is only shown to IE users. A more efficient method would be to use AJAX to include the javascript ONLY if the browser is IE, or of course, by implementing a server side browser detection library.
Avatar-eric-london
Created by Eric.London on 2009-08-09
Tags:
New Comment
 
Please note: the content on this page orginates from ericlondon.com.
In this tutorial I'll show you how you can add jQuery image carousel functionality to your CCK node. This tutorial requires you to install the following modules:


cck
filefield
imageapi
imagecache
imagefield


NOTE: The next few steps assume you have not already setup a content type and ImageCache preset. You can ignore them if you already have.

Once you installed the above modules and set permission accordingly, you'll need to define an ImageCache preset (/admin/build/imagecache/add). I called mine "thumbnail" for this example. I added a "Add Scale" action to set the width to 100 (pixels). This will ensure when you create an image, a thumbnail will be created automatically.



Create a new content type (/admin/content/types/add). I called mine "Carousel" for this example. I then clicked on "Manage Fields" (/admin/content/node-type/carousel/fields) to setup a new Image field. I called my new field "field_images", selected "File" for field type, and selected "Image" for the form element.



On the next screen, scroll down to the Global fieldset region and enable the "Required" checkbox, and set the "Number of Values" to "Unlimited". This will allow the user to upload numerous image files to the same CCK field.

Next, you'll want to set which image preset it shown when viewing the node, by clicking on "Display fields" (/admin/content/node-type/carousel/display). I chose the "thumbnail image" preset for both the teaser and full node displays.

I then created a new carousel node (/node/add/carousel). I used the "Add another item" button to upload three images to this node.



If you view the node, the images will be stacked vertically.



This is where the fun starts. You'll need to download the jQuery Carousel library (http://sorgalla.com/projects/jcarousel/). I downloaded the jcarousel.zip file and unpacked it. Copy the entire unpacked jcarousel folder into your theme directory.

Now, you'll need to add a preprocess_node function to your template.php file:

<?php
function YOURTHEME_preprocess_node(&$variables) {
  
  // test for carousel node type
  if ($variables['type'] == 'carousel') {

    // include jCarousel javascript
    drupal_add_js(path_to_theme() . '/jcarousel/lib/jquery.jcarousel.js');
    
    // add jquery in enable jQuery carousel on <ul>
    $js = "
      $(document).ready(function(){
        $('#mycarousel').jcarousel();
      });
    ";
    drupal_add_js($js, 'inline');
    
    // include jCarousel css
    drupal_add_css(path_to_theme() . '/jcarousel/lib/jquery.jcarousel.css');
    drupal_add_css(path_to_theme() . '/jcarousel/skins/tango/skin.css');
    
    // loop through images and create an item list
    $items = array();
    foreach ($variables['field_images'] as $key => $value) {
      $items[] = $value['view'];
    }
    
    // ensure images exist
    if (count($items)) {
      // add jQuery carousel html to $content variable
      $variables['content'] .= theme('item_list', $items, NULL, 'ul', array('id' => 'mycarousel', 'class' => 'jcarousel-skin-tango'));
    }
    
  }
  
}
?>


The previous code snippet should result in the following:



If you'd like you can hide the old image html by adding a single line of CSS (or by adding more elaborate code in your template preprocess function).

Example:

div.field-field-images {
  display: none;
}


Adding the previous CSS will result in this example:



UPDATE: This blog post is deprecated in favor of: http://drupal.org/project/jcarousel