Archive for the ‘open source’ Category

Toggle non-consecutive checkboxes with jQuery UI

Posted on:Tuesday, December 27th, 2011 by Ashish Datta

You’re all probably familiar with the UI convention of allowing users to select ALL or NONE for a list of checkboxes (like in Gmail). Recently I was working on a project that had a large table full of checkboxes (imagine a 10×10 grid) where the user would need to toggle some but not all of the checkboxes in a given row. And to make matters more complex, they would need to toggle groups of non-consecutive checkboxes (say 15, skip 10, 5, etc.). I threw on the thinking cap but couldn’t think of any similar interactions I’d seen and couldn’t think of a particularly good way to achieve this.

Enter jQuery UI. I happened to stumble across the jQuery UI Selectable documentation and realized it would provide a good UI experience to toggle some but not all of the checkboxes. The code to implement this is surprisingly simple:

Note: You don’t actually need the div container – that was just for JSFiddle.

<div id="checkboxes">

<table id="checkboxTable">
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
</table>
</div>

And then the Javascript (jQuery + jQuery UI):

$("#checkboxes").selectable( {filter: "input:checkbox",
            stop: function(event, ui) {

                $(".ui-selected").each( function(){

                    $(this).each( function(){
                        var val = $(this).attr("checked") ? null : "checked";
                        $(this).attr("checked", val);
                    });

                });
}});

You can check out a live demo at http://jsfiddle.net/whMyQ/3/

As always, questions and comments are welcome!

Facebook: How-to force users to LIKE page

Posted on:Friday, December 16th, 2011 by Ashish Datta

With Facebook’s move to deprecate FBML for tabs the documentation around how to make a “please Like! before…” has become much more choppy and inconsistent. Anyway, I recently found myself in a position where I needed to make this happen so here goes.

With in-line FBML deprecated, the only way to accomplish this without using a third party branded solution is to create a Facebook iframe app. Here are the steps you need to take to get something up using PHP and the Facebook PHP SDK.

1. Create a new Facebook Application at https://developers.facebook.com/apps

2. Configure your new Facebook App the enable “Website” and “Page Tab”. You’ll need to enter a valid URL for the following fields:

  • Site URL
  • Page Tab URL
  • Secure Page Tab URL

You’ll also want to use a HTTPs URL since Facebook sessions default to HTTPs by default and your iframe will be marked insecure if its over vanilla HTTP. For this walk through, lets assume were using https://www.setfive.com/fb/index.php? as the URL.

3. Now, you’ll want to add your new App to a Facebook Page. The easiest way to do this is to use this URL https://www.facebook.com/dialog/pagetab?app_id=YOUR_APP_ID&next=YOUR_URL replacing YOUR_APP_ID and YOUR_URL with your App ID and then a URL that is derived from your endpoint (or even just your endpoint). When you load that URL, you’ll be prompted to add your app to a page – select the page you want and submit the form.

4. The final piece is throwing together the actual PHP script. You’ll need the Facebook PHP SDK available on GitHub – https://github.com/facebook/php-sdk. Clone that and then this is the PHP script you’ll need:


<?php
require 'php-sdk/src/facebook.php';

$facebook = new Facebook(array(
  'appId'  => 'YOUR_APP_ID',
  'secret' => 'YOUR_APP_SECRET',
));

$req = $facebook->getSignedRequest();
?>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:fb="http://ogp.me/ns/fb#">

<head>
    <meta charset="utf-8" />
    <title></title>
</head>

<body>

<?php if( $req["page"]["liked"] ): ?>

	Content for users that have LIKED the page.

<?php else: ?>

	Content for users that HAVE NOT LIKED the page.

<?php endif; ?>

</body>

</html>

And thats it! Now you’ll be able to gate content from non-fans while growing the fanbase of your Facebook Page.

Drop any questions in the comments.

Fixing blank CCK Location fields in Views

Posted on:Sunday, September 25th, 2011 by Ashish Datta

Recently, we inherited a Drupal 6 site via a client of ours and ran into a pretty irritating bug with the Location module.

The site had been configured to allow users to create profiles using Node Profile along with the Location to allow users to input their street addresses.

Anyway, the issue was that when we created a View that included Location fields the fields were always rendering as blank even when we confirmed there was data in the database. A bit of poking around lead to this issue.

It turns out that due to an optimization in CCK or Views that the tables that have the data for the location fields are not getting JOIN’ed in when the view is executed. Unfortunately, the patch provided on the issue doesn’t work on the latest 3.x release of the Location module.

The fix that worked for us is #14 (copied below)

/**
* Preprocess hook for location().
*/
function yourtheme_preprocess_location(&$variables) {
  if (!isset($variables['location']['name']) && isset($variables['location']['lid'])) {
    $variables['location'] = array_merge($variables['location'], location_load_location($variables['location']['lid']));
    template_preprocess_location($variables);
  }
}

Basically, you’ll need to add the above snippet to a template.php file in your theme and change the name to reflect the theme you’re using. What this function does is basically pre-process the location fields to pull in the data so that the View will work properly.

Anyway, enough blogging it’s football time.

Adding a task/command in Symfony2

Posted on:Friday, September 9th, 2011 by Ashish Datta

I recently took the Symfony2 plunge and started working on a little fun side project (more on that later).

Anyway, this particular project involves sending out daily text messages using the rather awesome Twilio API so I decided to use a Symfony2 task for this. The documentation on how to actually add your own task is a bit sparse so I figured I’d share.

The process is actually pretty straight forward:

  1. In your bundle create a directory named “Command” (without the quotes).
  2. Create a file that extends ContainerAwareCommand
  3. Create a protected function configure – “protected function configure()” to allow you to configure the name of your task and add any options or arguments you might need.
  4. Create a protected function execute – “protected function execute(InputInterface $input, OutputInterface $output)” to actually do whatever needs to be done.
  5. Thats it! Now you can run app/console and you’ll see your task.

Here is the code for mine:

namespace Setfive\SextDejourBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class SendTextsCommand extends ContainerAwareCommand
{

    protected function configure()
    {
        parent::configure();

        $this->setName('sj:sendTexts')
             ->setDescription('Sends the day\'s sexts to everyone.');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {

         $ph = $this->getContainer()->get('doctrine')
                    ->getRepository("SextDejourBundle:Phonenumber")
                    ->createQueryBuilder("u")
                    ->getQuery()
                    ->getResult();

         $msg = $this->getContainer()->get('doctrine')
                    ->getRepository("SextDejourBundle:Message")
                    ->createQueryBuilder("u")
                    ->where("u.is_used = false")
                    ->setMaxResults(1)
                    ->getQuery()
                    ->getResult();
         $msg = array_pop( $msg );

         $msg->setIsUsed( true );
         // $this->getContainer()->get('doctrine')->getEntityManager()->flush();

         $accountId = $this->getContainer()->getParameter("twilio_app_id");
         $authToken = $this->getContainer()->getParameter("twilio_token");
         $myNumber = $this->getContainer()->getParameter("twilio_number");

         $client = new \Services_Twilio($accountId, $authToken);

         foreach( $ph as $p ){

           $sms = $p->getGender() == 0 ? $msg->getGuyText() : $msg->getGirlText();

           $res = $client->account->sms_messages->create ( $myNumber, $p->getPhoneNumber(), $sms );

           $output->writeln( $p->getPhoneNumber() . " => " . $sms );

         }

         return 0;
    }
}

jQuery UI confirm

Posted on:Monday, March 21st, 2011 by Ashish Datta

I was looking around earlier for a jQuery plugin to allow me to use jQuery UI’s dialog() widget to popup a confirm dialog. Didn’t have any luck finding one so I whipped something up. It’s not pretty but it works. You could even go as far as to overload window.confirm() but thats probably a bad idea.

jQuery.confirm = function(options){

	var opts = jQuery.extend( { message: "", ok: function(){}, cancel: function(){ } }, options );

	jQuery("
" + opts.message + "" + "
").dialog({ autoOpen: true, modal: true, autoOpen: false, resizable: false, draggable: false, title: "", width: "400px", buttons: { "Cancel": function(){ opts.cancel.call( this ); }, "Ok": function(){ opts.ok.call( this ); } } }).dialog("open"); }; // use it jQuery.confirm( { "message": "Are you sure?", "ok": function( ){ $(this).find(".loader:first").show(); // do stuff $(this).dialog("close"); }, "cancel": function( ){ $(this).dialog("close"); } });

Drupal 7: Batch insert nodes with Drush

Posted on:Wednesday, February 9th, 2011 by Ashish Datta

Well D7 has been out for a little while now and we finally got a chance to use it on a site this week.

Anyway, this site is one of the heavier Drupal sites we’ve done and it involved loading ~200+ nodes of data just to set things up. This presented two problems, how to batch load data and then how to load custom content types with several custom fields.

The Drupal module documentation has example code for adding a node with drupal_exeucte here but it doesn’t deal with how to set custom fields on your content type. On top of this, drupal_execute has been renamed to drupal_form_submit in Drupal 7 and the function signature has changed a bit.

Anyway, I dug around a bit and finally managed to get this working. You’ll obviously need Drush installed for the following code to work but you could rip it out and use it outside a Drush command. I was looking to basically replicate the “load-data” task from Symfony so that I could seed my Drupal database with Nodes at any point so I chose to make this a Drush command.

Here’s what you need:

- You’ll need a module to hold the Drush task. I used Module Builder to generate my scaffolding.
- Create a file named [modulename].drush.inc in your module directory
- Here is the code I’m using for [modulename].drush.inc Replace “cm” with the name of your module:


/**
* Implementation of hook_drush_command().
*/

function cm_drush_command() {

        // callback is the function that will be called when the command is executed
	$items['load-rep-data'] = array(
	    'callback' => 'cm_load_rep_data',
            'description' => 'Loads the representative data.',
            'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
	);

	return $items;
}

function cm_load_rep_data( ){
   // you need this to autoload the functions to create nodes
   module_load_include('inc', 'node', 'node.pages');

  // do some business logic to load your data from where it is
  foreach( $arr as $res ){

    // define the custom node type
    $node = array('type' => 'representative');

   // set up the form array
   $form_state = array();

   // set the title of the node
   $form_state['values']['title'] = $res["title"];

   // set a custom field that is a text type
   $form_state['values']['field_first_name']['und']['0']['value'] = $res["first_name"];

   // set a long text field and enable full_html - NOTE you'll need to allow anonymous users to use this for Drush to work
   $form_state['values']['body']['und']['0']['format'] = 'full_html';
   $form_state['values']['body']['und']['0']['value'] = $res["bio"];

  // set some custom select fields
  $form_state['values']['field_house_committees']['und'][ 0 ] = 34;
  $form_state['values']['field_house_committees']['und'][ 0 ] = 37;

  // can't leave this out or the form wont save
  $form_state['values']['op'] = t('Save');

  // actually try and "submit" the form
  drupal_form_submit('representative_node_form', $form_state, (object)$node);

  // printing from Drush is easy
  drush_print( $res["title"] );
  }
}

Thats about it.

With Firebug, it’s really easy to see the field names and the values that you can set by just looking at a form to create whatever type of node you want.

drupal_form_submit can also be used to “submit” any other type of form in Drupal.

An open question is how to “fill out” an ImageField field via the command line since nothing is actually going to be uploaded.

Received problem 2 in the chunky parser

Posted on:Sunday, December 26th, 2010 by Ashish Datta

I was using cURL in PHP to POST some data to a URL earlier tonight and ran into this problem.

With VERBOSE on cURL was erroring with the following error:

"Received problem 2 in the chunky parser"

After some Googling it turns out this is a problem with how some servers respond with chunked encoding.

A simple fix for this is to set the HTTP version cURL is using to 1.0:

curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 )

It’s not pretty but hey it works!

iPhone style checkboxes for Symfony

Posted on:Wednesday, October 13th, 2010 by Ashish Datta

No one worry, I did in fact survive my birthday and subsequent party!

Anyway, I was poking around for some cool UI elements for checkboxes and stumbled across this neat jQuery plugin – http://github.com/tdreyno/iphone-style-checkboxes Basically, what it does is converts checkboxes into iPhone style toggles.

Check out a demo at http://tdreyno.github.com/iphone-style-checkboxes/

This is for a symfony project (shocker!), so I figured I’d roll it into a widget and share.

You’ll need to download and include the JS+CSS+images for the plugin yourself and then copy the following code into your project:


class sfWidgetFormInputiPhoneCheckbox extends sfWidgetFormInputCheckbox {

	public function __construct($options = array(), $attributes = array())
	{

		$this->addOption('checked_label');
        $this->addOption('un_checked_label');

		parent::__construct($options, $attributes);
	}

	public function render($name, $value = null, $attributes = array(), $errors = array())
	{
		$str = parent::render( $name, $value, $attributes, $errors );

		$checkedLabel = $this->getOption("checked_label");
        $uncheckedLabel = $this->getOption("un_checked_label");
        $id = $this->generateId($name);

		$str .= <<

		  $(document).ready( function(){

                $('#$id').iphoneStyle({
                    checkedLabel: '$checkedLabel',
                    uncheckedLabel: '$uncheckedLabel'
                });

		  });
		
EOF;

		return $str;
	}

}

Using it is straightforward:

    $this->setWidgets(array(
      'show-upcoming-events-nav' => new sfWidgetFormInputiPhoneCheckbox( array("checked_label" => "on", "un_checked_label" => "off") ),
    ));

ahDoctrineEasyEmbeddedRelationsPlugin and Composite Primary Keys

Posted on:Friday, September 3rd, 2010 by Matt Daum

We”ve been working on a project in which a bunch of the tables had composite primary keys.  Often we wanted to embed these tables in other forms.  ahDoctrineEasyEmbeddedRelationsPlugin is a great plugin for managing embedded forms with Doctrine and Symfony.  It lets you easily let users add multiple new relations and delete previous ones.   However, it didn’t really support composite keys.   We also wanted to be able to expose the primary keys rather than unsetting them from the form(so that the relation is automatically declared).  This was a problem as we needed to be able to select at least one of the primary keys.  Here is an example where we wanted to let the user pick one of the primary keys:

User:
  columns:
     first_name:
        type: string(16)
Product:
   columns:
      name:
         type: string(32)
UserProduct:
   columns:
      user_id:
         type: integer
      product_id:
         type: integer
        price:
          type: decimal
    relations:
       User:
          local: user_id
          foreign: id
       Product:
         local: product_id
         foreign: id

In this case there are Products and Users. A Users can have a products and specify how much each costs. When you are adding products to a user, you would want to be able to select which product you are adding in the embedded form. This is where our problem was, with the plugin as of version 1.4.4 you couldn’t tell it not to unset the primary keys when it embedded the form. We did a checkout of the plugin from SVN and modified it a bit. It now has and additional parameter: newFormUnsetPrimaryKeys . This will make it so the plugin will not unset the primary keys on a new form if you set it to true (it defaults to false).

We also found that the plugin had hard coded a couple of places findOneById which required the primary key to be called `id`. We’ve updated this to use the Doctrine method getIdentifierColumnNames() to get the primary keys.

We only applied to be developers on this script, so are currently waiting on it to be packaged and released, however if you want our updated just do a svn checkout of the plugin and you will be all set!

Let us know if you have any questions on it!

UPDATED: New Facebook Phonebook Script

Posted on:Monday, July 19th, 2010 by Ashish Datta

I realized this morning that Anonymous Coward’s Facebook Phonebook Greasemonkey script broke awhile back so I decided to rewrite it from scratch.

The original instructions for how to install the script are available here.

I updated the original Userscripts page with the new script so you can download it here.

Once again, this probably breaks your Facebook TOS so I can’t vouch for the safety of your account if you do decide to do this.