Sunday, October 7, 2012

Changing Dancer::Plugin::Ajax's content type

Dancer does lots of great things. It has a nice clean way to define routes to handle AJAX routes using the plugin Dancer::Plugin::Ajax.

ajax routes are defined in a clear way:

ajax '/stuff' => sub {
  # do work and return
};

This plugin technique allows for clear way to separate between ajax and other types of actions for the same route.

ajax '/stuff' => sub {
   # do ajax-y stuff here
};

get '/stuff' => sub {
   # handle html response
};

Unfortunately, the one negative with Dancer::Plugin::Ajax is that is assumes all responses will be XML.

A quick fix is to manually set the content type in each ajax handler.

ajax '/stuff' => sub {
   content_type('application/json');
   
   # do work
};
or add set it as a general option in your main before hook or in each prefix route handler like:
package WebApp;

hook before => sub {
   if ( request->is_ajax ) {
      content_type('application/json');
   }
};

Both of these solutions feel kind of clunky due to the level of duplication. Our app returns JSON or HTML snippets and never uses XML. This redundancy in code led me to creating a patch for Dancer that allows default Ajax content_type to be set in the config file. (see issue 840).

Config Example:

  plugins:
    ajax:
      content_type: 'application/json'

__END__

Tuesday, September 25, 2012

Blueberry (Image slider) and YouTube video working in harmony

Do what needs to be done

We recently launched a new home page and the designed used a responsive image slider called Blueberry. Well there were a few issues with navigation and I needed to be able to make sure to have the slider start to slide automatically and then stop while playing a YouTube video.

I need to fix the problem with navigation causing a speed up and unreliable timing while showing slides. I extended it to support being stopped and started. Since the project appears to be on hiatus (no changes in a year even though it has a few github issues), I forked it on github to fix the event issue and add the ability to stop/start slider.

Blueberry + YouTube sitting in a tree

I found it to be a bit of challenge to update the site to support pausing the image slider when the YouTube video that is linked in through iframe started and stop being played. I found to get the correct permissions and callback into the player I needed to use the YouTube iFrame Player API. (thank you Google)

To setup the Blueberry slider, there is some basic html
(and css see: https://github.com/lecar-red/Blueberry/blob/master/index.html).

Here is a blurb of html


Next is the Javascript code to setup the slider:

$(function() {
  $('.blueberry').blueberry({hoverpause: true});
});

Now the image slider will start up showing images (and YouTube video).

Next comes dropping in the YouTube API, plus adding in the callback controls. The following snippet of JS code contains all of the code needed to start and stop slider when video is played and stopped by user. I'll explain it in the following sections.


1. The first closure is to load the youtube js API script. 

2. onPlayerStateChange is a function that is called each time the player changes state, it is passed an event object with what type of change occurred see the details in the YouTube API Docs.  

2a. This code will pause the slider when the video is playing (when event type is PLAYING). 

2b. When data event is type is PAUSED or ENDED restart slider. The Blueberry slider's code will restart the timeout interval at start and stop so it won't necessarily change right away. I could see expanding this code to only start when the video was ended in our case it wasn't required.

3. Create new API object and save player to global object (this could be done a bit cleaner by storing in a global object or something else - exercise for the reader :)

Once I waded through the various APIs, browser cross domain restrictions and code patches. The end solution wasn't too bad. The above YouTube API code could be used with any slider or carousel.

__END__

Saturday, August 25, 2012

Template Tooltip Tip #1

A bit of background

Template toolkit is a powerful and mature Perl based templating engine. It is designed to be output format agnostic and used (or able to be used) with most of the Perl based Web application frameworks like Dancer, Catalyst and CGI::Application.

TT Tip #1 - Simple html attribute macro

In this tip, i'll combine using a TT macro with HTML plugin to create a simple macro to add active class to html element.

code

TT code: (put in top of template or shared TT file pulled in with PROCESS or INCLUDE)
[% USE HTML %]
[% MACRO active GET HTML.attributes( 'class' => 'active' ) %]

Usage in a template:

<ul id="navBar"> 
  <li [% active IF page.name == 'home' %]>Home</li>
  <li [% active IF page.name == 'about' %]>about</li>
  <li [% active IF page.name == 'contact' %]>contact</li>
</ul>

In this case, when page.name matches then macro will drop in class="active". Simple but much more readable then a bunch of statements like:
[% IF page.name == 'home' %]class="active"[% END %]

I'm sure there are more elegant ways to create menu bar or breadcrumbs but this is intended to give you a feel of using a TT macro.

block with a process or include could be used but that ends up with template code like [% PROCESS active IF page.name == 'home' %] but i think the macro call is clearer with less directive line noise.

  __END__

Thursday, July 12, 2012

5 minute guide to using JS PubSub and Noty

5 minute guide to using PubSubJS and Noty

A little background, Publish/Subscribe is a design pattern for decoupling components in software (or i guess anywhere in the world). The basic idea is that one thing publishes information to a well known place and another subscribes to it. There is lots of good writing about it out there, check it out on Wikipedia.

In my situation we wanted to display page level notifications. I would consider these to be messages that aren't tied to a web widget or element (like a message in a form). Page level notifications can increase the usability of your application (too many or badly placed one can reduce it :)

This tutorial will show you a simple way to create a subscriber that publishes messages to the browser using noty. And uses PubSubJS to handle the Publish/Subscribe work.

The tools

You will need a few things for this tutorial.
Grab them and download, or you can try this shell snippet:
  mkdir js
  wget https://raw.github.com/needim/noty/master/js/jquery.noty.js
  wget https://raw.github.com/mroderick/PubSubJS/master/src/pubsub.js
  cd ..
  mkdir css
  wget https://raw.github.com/needim/noty/master/css/jquery.noty.css
  wget https://raw.github.com/needim/noty/master/css/noty_theme_twitter.css

The whys

In our application, we needed to publish messages in the top of the application page. We use bootstrap and the noty plugin provided a perfect fit since it supports top (or anywhere else) notifications plus it matched the style of bootstrap alerts. It has an active developer as well.
There are many (many, many, many) Javascript PubSub implementations but PubSubJS seems the most lively and felt the most mature. In reality there are many good ones.

Getting Started

You will need to include PubSub and noty in your page with standard script and style html tags.

Also, all the code I"m including below should be put in a jQuery on load page closure. Example:

$(function() {
  // code goes here
});

Setup of noty options

First lets setup our noty library to display messages. After including the libraries in your page (using standard css and js html tags), In a page load closure set the following:

noty allows setup of most options when making the explicity call to the library:

$.noty({
  text: 'noty - a jquery notification library!',
  theme: 'noty_theme_twitter'
});

But this will become a pain, esp since we want all the notifications to use the same theme anyway. Nicely noty gives a way to setup all the options before creating individual notfications.

In the end, we only really need to set two default options:
  • theme - set everything to use the twitter option
  • closeButton - show button to close notification
Global Setup:
$.noty.defaultOptions.theme       = 'noty_theme_twitter';
$.noty.defaultOptions.closeButton = true;

You can see all the options at noty docs.

Using noty

Creating a noty is pretty quick and simple but before I drop the code in later in a subscriber, it seems best show and example an example now.

Example:
$.noty({ type: 'error', text: 'Arghhh getting eaten by zombie!' });

This will create a nice little alert at the top of your page. type parameter is used to figure what type of notification (and formatting to show) to show. text is what is shown to the user.

Setup of PubSubJS and message queues

Using pubsub requires two functions. A subscriber (that listens and acts on messages in a queue) and a publisher which sends a message (really just a data structure) to a queue. I guess there is a third item to setup but its more or less implicit that is the queue. In this situation the queue is created when either a publisher or subscriber specifics a queue.

The PubSubJS docs recommend using a variable name for a given queue name. I think that is often a good idea but in this case I don't plan on doing it :)

Subscriber

Since we have a pretty good idea of what the subscriber needs to do. I think creating the subscriber first makes sense.

The subscriber will need to listen on a queue and display each message coming in. In this situation, we want to be able to pass an array of messages.

Data format:
[
   { 'type': msgtype, 'text': msgtext },
   ... more if needed ...
]
Example:
PubSub.subscribe( 'site.messages', function( topic, msgs ) {
  var msgs = $.isArray(msgs) ? msgs : [ msgs ];
  $.each( msgs, function() { $.noty( this ) } );
});

that is it. That will listen to subscriber and show each message coming in. As I look at the code (after a few weeks), I added an auto convert msgs to an array.

Publisher

The publisher will be embedded in some other globber of code. I've used this type of call in ajax form handlers, click events and even some code that runs at page load time to show messages generated when the pages are produced from the server.

Example:
PubSub.publish( 'site.messages', 
   { 'type': "success", 'text': 'Successfully updated thingy' });
Use inside of events

I find it helpful to see an example of this in use i real-ish code. Here is a boring click handler for a button (or anything really) that will show a message

$('body').on('click', '.show-message', function(e) {
   PubSub.publish( 'site.message',
     { type: 'warning', "Watch for falling rocks!' });
   return false;
});

I hope you found some use in this guide, please let me know if you have any comments or questions

__END__

Tuesday, July 3, 2012

Using (Test::?)WWW::Mechanize to test AJAX calls

Test::WWW::Mechanize + AJAX = Love?

As we use more and more client side driven forms, testing in a standard way for unit/expanded unit tests becomes more and more difficult.

I've been in the process of creating more use case tests so as underlying components in our system changes those non-web people can verify that their changes don't break the webapp. 

This is often our REST API but can apply to DB changes or modules updates.

I've found this basic code block to work pretty well at using Test::WWW::Mechanize to simulate the situations where there are elements that use client side forms. (AJAX! But really AJAJ since we use JSON instead of XML).


BEGIN {
  use Test::More;
  use Test::Exception;
  use Test::WWW::Mechanize;
  use JSON;
}

#
# setup test data or load it from db
#

# 
# in this test, i login w/ many page, jump to account page
# then run ajax form and check json results
#
{
   diag "Running login and create user test";
   my $mech = Test::WWW::Mechanize->new;
   
   # base is defined above :)
   $mech->get_ok(sprintf('%s%s', $base, '/user/login'));

   # login
   $mech->submit_form_ok({
        #might be best to add name to enroll form
        form_number => 1,
        fields      => {
            email     => $test_email,
            password  => $test_password,
        }
    }, '/user/login');

    # goto next page
    $mech->get_ok( sprintf( '%s%s', $base, '/users' ));
    
    # in my case the form doesn't exist on the page until js 
    # code is run so we have to pretend to know it
 
    # pretend to be ajax client
    $mech->add_header( 'X-Requested-With' => 'XMLHttpRequest' );

    # form url
    my $create_url = sprintf '%s%s', $base, '/user/create';

    #
    # this is a failure case
    #
    my $resp  = $mech->post( $create_url, $bad_user_params );

    lives_ok { $jresp = from_json( $mech->content ) }
      'invalid user - json returned';
    
    # check response for errors and specific fields, YMMV
    is scalar @{$jresp->{errors}}, 5, 'missing fields';
    ok grep { qr/confirm_email/ } @{ $jresp->{errors} },
       'errors - confirm_email';
}

Its a bit of a long example but the real magic happens with adding the header to the request with $mech->add_header line, you will probably need to go back to standard requests by removing that header with $mech->delete_header('X-Requested-With').

Next series of my tests will be doing this with forms that exist in the page. I suspect that it may take a bit of fiddle with WWW::Mech.

 __END__

Wednesday, May 30, 2012

bootstrap popover responsive layout

As i was working on solving some problems with Bootstrap's popovers and our responsive webapp design, I came up w/ this simple snippet to change the location of the popover using placement option using the current window's width.

Example of how to set placement using function:

$('.show-details').popover({
  placement: function(tip, ele) {
    var width = $(window).width();
    return width >= 975 ? 'left' : ( width < 600 ? 'top' : 'right' );
  }
});

In the long run i think it would make more sense to setup those location options in a map or site wide setting object along the lines of:

var superapp = {};

superapp.popover_layouts = {
   full:  { width: 975, pos: 'left'},
   mid:   { width: 600: pos: 'right'},
   micro: { width: 320: pos:  'top' }
};

function determine_placement(tip, ele) {
   var width = $(window).width();
   var map   = superapp.popover_layouts;

   .... TBD .... :)
}

I'm not sure I'm crazy about that. I wonder if using media queries is a better option. In our situation we will need to adjust the class on each popover.

Probably need a bit more thought on it all.

 __END__

Monday, May 21, 2012

Bootstrap popover with function driven content

In another post, I wrote about a technique that allowed loading content into a popover using a function.

Its a great feature but I found one gotcha. If you set anything in the data-content attribute on the trigger element, the content will not be loaded with the function.

Maybe I should say that again for myself, If you want to use content: function() {...} your element must not include data-content

Don't use:
<a id="mypopover" href="#" 
   data-content="will not run function"> Label </a>
Use:
<a id="mypopover" href="#" > Label </a>
__END__

Thursday, April 5, 2012

BootstrapX clickover

Birth


The last few weeks, i've been pushing Bootstrap in various directions. Most of the time, its being hacking around Popovers. Our current design uses Popovers with forms. It provides a very nice balance between in page action and more subtle interruption to viewing the page than a modal.

Over the last few weeks, I've found a few quirks with using Popover's trigger action of 'focus'. This works fine with forms but on Chrome and Safari 'focus' events are supported incompletely. In addition to that varied support we have a few other needs that inspired a new Bootstrap extension. BootstrapX - Clickover.

Our requirements are:
  • Click button/link/icon to toggle display of popover content
  • Option to click 'away' from popover to close
  • Ability to have 'popover' autoclose after some amount of time
  • Option to have element inside of popover hide it

I suspect, in the future, it will need to only auto close when user's mouse leaves the clickover.

Out of these needs spawed the library: bootstrapx-clickover.

Usage Examples


Basic


html:
<button rel="clickover" 
  data-content="Show something here. 
    <button data-dismiss='clickover'
    >Close Clickover</button>"
>Show clickover</button>

javascript:
// load click overs using 'rel' attribute
$('[rel="clickover"]').clickover();

For more complex details and examples check out:
__END__

Thursday, March 8, 2012

Bootstrap (by Twitter) loading in page content for Popovers

Bootstrap is a nice get started HTML/CSS/JS interface toolkit. At $work our newest design has been based on it and many of its components.

One of the challenges I've run into with the Popover element is generating in attribute content for complex elements.

The basic context is:
<a id="mypopover" href="#" data-content="stuff to display"> Label </a>

The popover gets the body from the data-content attribute. The other option that doesn't appear to be documented is using a function set in the options.

$('#mypopover').popover({
   // other options here
   content: function(ele) { return $('#popover-content').html(); }
});

This will load the html content from element '#popover-content' when calling 'show' on popover.

Note: If trigger element still has a data-content element, even if its empty, the content function will not be called by method.

My biggest issue still with Bootstrap tools is that they are not generally designed to be used with externally loaded content. Therefore to load this type of content I still need to setup lots of manually event handlers. It seems like jQuery Tools has a bit more complete event model today. But Bootstrap is still very young.

__END__

Tuesday, February 21, 2012

Sticky floating headers inside of overflowing divs

In our latest project, we have some pretty sweet designs that have headers that drift down in the page as the user scrolls. But at some point the header will hit the end of the containing div and need to stop. (We have a date header for each transaction. The header stops floating once the next day's header is met in the scroll).

We had some luck using jquery plugin based on a good tutorial at Design Woop mixed with this updated Gist

But this fell apart when trying to use it with a div that had overflow set to 'auto' or 'scroll'. Since the plugin was calculating location based on document not the div element. Plus the plugin operated on single elements not on jquery objects.

CSS Looks like:
div.scroll {
        background-color: #eee;
        width: 600px;
        height: 200px;
        overflow:scroll;
      }

      .header {
        float: left;
        height: 30px;
        width: 600px;
        background-color: black;
        color: white;
        font-family: 'Times New Roman', serif;
        font-size: 20px;
      }

And html markup looks like (i've removed the extra text so it many not flow based on screen size and such).

html:
<div class="scroll">
  <div class="header" id="nowrapper">This is a header</div>
  <br class="clear">
   text here
  <div class="inside">
    <div class="header" id="lower">Lower Header</div>
    <br class="clear">
    more text here
  </div>
</div>

I couldn't find the plugin anywhere so I dumped it up in: https://github.com/lecar-red/jquery-stickyfloat and added support for floating inside a overflowed div.

To make that page work, after downloading updated stickfloat then add this javascript:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.stickyfloat.js"></script>
    <script type="text/javascript">
      $(function() { $(.header).stickyfloat({}) } );
    </script>

I'm hoping to put a tutorial but that will need to wait until another day. You can see how to use it in: https://github.com/lecar-red/jquery-stickyfloat/blob/master/overflow.html

__END__

Monday, January 23, 2012

New CPAN Module: WWW::DirectAdmin::API

New module for interacting with DirectAdmin's API: WWW::DirectAdmin::API

It currently supports User level functions only. More to come later

__END__

Monday, January 16, 2012

Accessing Dancer config settings inside of a template

As I continue to work more and more with Perl Dancer, I run into situations where I need to pull in application configuration data inside of the template system.

Dancer provides access to this config in your template system with the template token settings. What caught me the other day was my desire to use it in the same way as the in the app's DSL: setting. This was my misreading of the documentation. To access settings in Template Toolkit, you must grab sub areas as hash keys.

Example: (you can see this in the generated new app code)
App name: [% settings.appname %]
I did have a case where I wanted to pull in a value that was located in the plugin section. The plugin (like some of them) are named with double colons (::) and I couldn't get the hash key lookup to work so I used TT's item virtual method.

This example dumps out RSS version:
Using RSS Output Version: 
[% settings.plugins.item('XML::RSS').output %]

Disclaimer: Of course in the case of some configuration values it might make more sense to update the plugin code to share the value or add a before template hook to pass it out.

__END__