Pseudo Techie and Hazy Dreams:

Friday, November 27, 2009

Contextual help quickly

Today's problem: I needed to add contextual help for each and every screen in web application for the end user.
This can be invoked by either clicking on the help icon or the pressing hot-key e.g. key h

You have to maintain the key value map of key identifier for each screen and corresponding help html/text.

In normal java web application which is using sitemesh decorators; we can set global variable identifying each and every screen uniquely.
For example below is the snippet from the decorator.






Following snippet to bind key 'h' to function which shows the help


$(document).keydown(function(e){
if (e.keyCode == 72) { //h key
getHelp();
return false;
}
});


Help function as well as map for the function as below.

var HelpMap ={
"menu1" :"menu 1 help",
"menu2" : "menu 2 help"
....
...
}

function getHelp()
{
if(!$('.selectedScreen').attr('id'))
return;

id= $('.selectedScreen').attr('id');

if(!HelpMap[id])
return;

$("#helpDialog").html(HelpMap[id]);
$("#helpDialog").dialog( 'open');
$("#helpDialog").dialog({
bgiframe: true,
resizable: true,
height: 250,
width: 350,
modal: false
});

}


Function assumes that you have screen element which has id with unique entry in the help map.
Thats it!



Thursday, November 26, 2009

Adding jquery datepicker as filter to jmesa grid

Jmesa no doubt is great library for java based web applications. Here is the quick way to add date/dateTime filtering to jmesa grid.

Add following snippet to jquery.jmesa js file. So that we can invoke this api from the custom AbstractFilterEditor i.e. DateRangeFilterEditor


var dynDateFilter = null;
//add following function stub to filterapi object.
createDynDateFilter : function(filter, id, property) {
if (dynDateFilter) {
return;
}

dynDateFilter = new classes.DynFilter(filter, id, property);

var cell = $(filter);
var width = cell.width();
var originalValue = cell.text();

/* Enforce the width with a style. */
cell.width(width);
cell.parent().width(width);
cell.css('overflow', 'visible');

cell.html('
'
+'
');

var input = $('#dynFilterDateInput');
$("#dynFilterDateInput").datepicker({
duration: '',
dateFormat: 'yy-mm-dd',
showTime: false,
constrainInput: false
});
input.val(originalValue);
input.focus();

$(input).keypress(function(event) {
if (event.keyCode == 13) { /* Press the enter key. */
var changedValue = input.val();
cell.text('');
cell.css('overflow', 'hidden');
cell.text(changedValue);
$.jmesa.addFilterToLimit(dynDateFilter.id, dynDateFilter.property, changedValue);
$.jmesa.onInvokeAction(dynDateFilter.id, 'filter');
dynDateFilter = null;
}
});

$(input).change(function() {
var changedValue = input.val();
cell.text('');
cell.css('overflow', 'hidden');
cell.text(changedValue);
$.jmesa.addFilterToLimit(dynDateFilter.id, dynDateFilter.property, changedValue);
$.jmesa.onInvokeAction(dynDateFilter.id, 'filter');
dynDateFilter = null;
});
}


Code for DateRangeCellEditor, pretty straight froward


public class DateRangeFilterEditor extends AbstractFilterEditor
{
@Override
public HtmlColumn getColumn()
{
return (HtmlColumn)super.getColumn();
}

public Object getValue()
{
HtmlBuilder html = new HtmlBuilder();

Limit limit = getCoreContext().getLimit();
HtmlColumn column = getColumn();
String property = column.getProperty();
Filter filter = limit.getFilterSet().getFilter(property);

String filterValue = "";
if (filter != null)
{
filterValue = filter.getValue();
}

html.div().styleClass("dynFilter");
html.onclick("jQuery.jmesa.createDynDateFilter(this, '" + limit.getId() + "','" + column.getProperty() + "')");
html.close();
html.append(escapeHtml(filterValue));
html.divEnd();

return html.toString();
}
}


And you need to have FilterMatcherMap too.



public class PDADateFilterMatcherMap implements FilterMatcherMap
{

public Map getFilterMatchers()
{
Map filterMatcherMap = new HashMap();
filterMatcherMap.put(new MatcherKey(Date.class, "importDateTime"), new DateFilterMatcher("yyyy-MM-dd"));
return filterMatcherMap;
}
}


Declare CellEditor,FilterMatcherMap in jmesa tags as below.








Thats it!



Saturday, June 13, 2009

Jquery+JMaps+ Trekking spots in Sahyadris

Here is the quick recipe of the small utility hobby application I wrote some time back. This application adds marker to lot of trekking places in Sahyadris ranges in Maharashtra. Thanks to fantastic jmaps library it made it simpler for me.

So here we go.

  • First step I needed to hold all latitude/longitude data in a format which can be easily consumed by my logic written in JavaScript. So I put everything in JSON arrays named places as follows. And kept this in a separate file called as places.json

{"places":[
{ "name":"Alang",
"lat":"19.58268",
"long":"73.66229",
"elevationFeet":"4852",
"elevationMeter":"1479",
"submittedBy":"Mahesh Chengalva"
}.....n records
]
}

  • On load I make call to JSON file as mentioned above and pass callback function which is added below after this snippet.


(function($){
$.getJSON("places.json", loadMapInformation);
})(jQuery);


  • Once you handle the data part and follow sample examples mentioned on jMaps page you can code google-maps application very easily. Following function does everything required for this maps application. I love Jquery and more than that I like Jquery Plugin architecture so that we can have such wonderful plugins which make life easier.


function loadMapInformation(locationMapInfo){

$('#map').jmap(
'init',
{
mapCenter:[19.38685, 73.77917],
mapType:'hybrid',
mapEnableType:true,
mapZoom:11,
mapEnableScrollZoom:true,
mapEnableSmoothZoom:true
}
);
// add links to right-hand sidebar
$.each(
locationMapInfo.places,
function(i, location)
{
$("
  • "+location.name+"
  • ").appendTo("#links");
    }
    );
    // add markers on Map and html-content to be shown on click of marker
    $('#links a').each(
    function(n){
    $('#map').jmap(
    'addMarker',
    {
    pointLatLng:[locationMapInfo.places[n].lat,locationMapInfo.places[n].long],
    pointHTML:"Place :"+locationMapInfo.places[n].name+"
    "
    +"Elevation :"+locationMapInfo.places[n].elevationFeet+" Feet("+locationMapInfo.places[n].elevationMeter+" Meters)
    "
    +"Contributed By :"+locationMapInfo.places[n].submittedBy+"
    "
    }
    );
    // also add click handler for sidebar clicks
    $(this).bind('click',
    function(event) {
    $('#map').jmap(
    "moveTo",
    {
    mapCenter: [locationMapInfo.places[n].lat,locationMapInfo.places[n].long],centerMethod: "pan"
    }
    );
    }
    )
    }
    );
    }



    Erlang : Quick setup on Ubuntu


    1. sudo apt-get install erlang-base
    2. sudo apt-get install erlang-base-hip

    Once you are done. Head to getting started page on erlang website. Its fun to learn new language.



    Saturday, May 9, 2009

    Notes : Coding and Debugging

    Source: Practices of an Agile Developer - Working in the Real World

    • Program intently and expressively : This summarises whole post literally but read on. Details are important in real life.
    • Code you write must clearly communicate your intent and must be expressive. By doing so, your code will be readable and understandable. Since your code is not confusing, you will also avoid some potential errors.
    • Write a code that is easy to understand.
    • Code iteratively. Have continuous feedback loop ready.
    • Elegant code is immediately obvious in its utility and clarity. But the solution isn’t something you would have thought of easily. That is, elegance is easy to understand and recognize but much harder to create.
    • Develop the simplest solution that works. Incorporate patterns, principles, and technology only if you have a compelling reason to use them. Side Note for me: Thats the way to understand the framework and their purpose. Don't jump start projects based on the frameworks w/o studying why part.
    • Cohesive coding: We follow this in patterns. packages/modules and tiered apps. MVC pattern etc. Each artifact does ONLY one thing very well. this simplifies refactroing and testability of your application.
    • Command-Query separation: Command likes to change the state of the object and returns some value also. Query just returns the state of the object. This separation is important to avoid side-affects. Design time decisions and keep your unit tests ready for this.
    • Substitute by contract: Derived class should "require no more and promise no less than" the methods/services available in the base class.Make a decision based on type of relationship is-a/has-a/uses-a. Delegation is usually more flexible and adaptable than inheritance.Use interfaces in the form of delegation but make sure what interface really promises or requires.



    Friday, April 3, 2009

    Book to read: Refactor Your Thinking Pragmatic Thinking and Learning