Friday, March 7, 2014

Overloading or Extending standard GORM CRUD methods


class BootStrap {
    def grailsApplication;

    def init = { servletContext ->
        grailsApplication.domainClasses.each {
            def domainClass = it;

            def savem = domainClass.metaClass.getMetaMethod("save");
            domainClass.metaClass.save = {
                // do your before save work here...
                def ins = savem.invoke(delegate);
                // do your after save work here...
                return ins;
            }

            def savem2 = domainClass.metaClass.getMetaMethod("save", Map);
            domainClass.metaClass.save = { Map paramMap ->
                // do your before save work here...
                def ins = savem2.invoke(delegate, paramMap);
                // do your after save work here...
                return ins;
            }

            def deletem = domainClass.metaClass.getMetaMethod("delete");
            domainClass.metaClass.delete = {
                // do your before delete work here...
                def ins = deletem.invoke(delegate);
                // do your after delete work here...
                return ins;
            }

            def deletem2 = domainClass.metaClass.getMetaMethod("delete", Map);
            domainClass.metaClass.delete = { Map paramMap ->
                // do your before delete work here...
                def ins = deletem2.invoke(delegate, paramMap);
                // do your after delete work here...
                return ins;
            }
        }
    }
    def destroy = {

    }
}

jQuery get browser and os details

http://jquery.thewikies.com/browser/


$(document).ready(function () {
    $.browserTest = function (userAgent, z) {
        var u = 'unknown', x = 'X';
        var getBrowserName = function (userAgent, userAgents) {
            for (var i = 0; i < userAgents.length; i = i + 1) {
                userAgent = userAgent.replace(userAgents[i][0], userAgents[i][1]);
            }
            return userAgent;
        }
        var getBrowserDetails = function (userAgent, browserNameRegex, layouts, browserVersionRegex) {
            var r = {
                name: getBrowserName((browserNameRegex.exec(userAgent) || [u, u])[1], layouts)
            };
            r[r.name] = true;
            r.version = (browserVersionRegex.exec(userAgent) || [x, x, x, x])[3];
            if (r.name.match(/safari/) && r.version > 400) {
                r.version = '2.0';
            }
            if (r.name === 'presto') {
                r.version = ($.browser.version > 9.27) ? 'futhark' : 'linear_b';
            }
            r.versionNumber = parseFloat(r.version, 10) || 0;
            r.versionX = (r.version !== x) ? (r.version + '').substr(0, 1) : x;
            r.className = r.name + r.versionX;
            return r;
        }
        userAgent = (userAgent.match(/Opera|Navigator|Minefield|KHTML|Chrome/) ? getBrowserName(userAgent, [
            [/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/, ''],
            ['Chrome Safari', 'Chrome'],
            ['KHTML', 'Konqueror'],
            ['Minefield', 'Firefox'],
            ['Navigator', 'Netscape']
        ]) : userAgent).toLowerCase();
        console.log(userAgent);

        $.browser = getBrowserDetails(userAgent, /(camino|chrome|firefox|netscape|konqueror|lynx|msie|opera|safari)/, [], /(camino|chrome|firefox|netscape|netscape6|opera|version|konqueror|lynx|msie|safari)(\/|\s)([a-z0-9\.\+]*?)(\;|dev|rel|\s|$)/);
        console.log($.browser);

        $.layout = getBrowserDetails(userAgent, /(gecko|konqueror|msie|opera|webkit)/, [
            ['konqueror', 'khtml'],
            ['msie', 'trident'],
            ['opera', 'presto']
        ], /(applewebkit|rv|konqueror|msie)(\:|\/|\s)([a-z0-9\.]*?)(\;|\)|\s)/);
        console.log($.layout);

        $.os = {
            name: (/(win|mac|linux|sunos|solaris|iphone)/.exec(navigator.platform.toLowerCase()) || [u])[0].replace('sunos', 'solaris')
        };
        console.log($.os);
    }
    $.browserTest(navigator.userAgent);
});

Native Fullscreen JavaScript/jQuery API

http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/

My name pritom


jQuery code


$(document).ready(function () {
    var fullScreenCheck = $("div#main-body").checkFullScreen();
    if (fullScreenCheck.enter && fullScreenCheck.exit && fullScreenCheck.fullscreen && fullScreenCheck.change && fullScreenCheck.error) {
        $(document).bind(fullScreenCheck.change, fullScreenChangeHandler);
        $(document).bind(fullScreenCheck.error, fullScreenErrorHandler);
        $(".fsmode").html("Full screen would work...");
        $("div#main-body .fullscreen").click(function () {
            if(document[fullScreenCheck.fullscreen]) {
                console.log("Going to normal screen...");
                document[fullScreenCheck.exit]();
            } else {
                console.log("Going to full screen...");
                $("div#main-body")[0][fullScreenCheck.enter]();
            }
        })
        $("div#main-body").click(function () {
            $(document).trigger("fullscreenchange");
        })
        $(document).bind("fullscreenchange", function() {
            if (document[fullScreenCheck.fullscreen]) {
                $(".fsmode").html("Window is now full screen...");
            } else {
                $(".fsmode").html("Window is now normal screen...");
            }
        });
    } else {
        $(".fsmode").html("Full screen would not work...");
        $("div#main-body .fullscreen").remove();
    }

    function fullScreenChangeHandler(event) {
        $(document).trigger(new $.Event("fullscreenchange"));
    }

    function fullScreenErrorHandler(event) {
        console.log(event.originalEvent);
    }
})

jQuery.fn.checkFullScreen = function () {
    var enter, exit, fullscreen
// support for entering fullscreen
    var dom = document.createElement('div');
    if ('requestFullscreen' in dom) {
        enter = 'requestFullscreen' // W3C proposal
    } else if ('requestFullScreen' in dom) {
        enter = 'requestFullScreen' // mozilla proposal
    } else if ('webkitRequestFullScreen' in dom) {
        enter = 'webkitRequestFullScreen' // webkit
    } else if ('mozRequestFullScreen' in dom) {
        enter = 'mozRequestFullScreen' // firefox
    } else if ('msRequestFullscreen' in dom) {
        enter = 'msRequestFullscreen' // ms
    } else {
        enter = null // not supported in this browser
    }
// support for exiting fullscreen
    if ('exitFullscreen' in document) {
        exit = 'exitFullscreen' // W3C proposal
    } else if ('cancelFullScreen' in document) {
        exit = 'cancelFullScreen' // mozilla proposal
    } else if ('webkitCancelFullScreen' in document) {
        exit = 'webkitCancelFullScreen' // webkit
    } else if ('mozCancelFullScreen' in document) {
        exit = 'mozCancelFullScreen' // firefox
    } else if ('msExitFullscreen' in document) {
        exit = 'msExitFullscreen' // ms
    } else {
        exit = null // not supported in this browser
    }
// support for detecting when in fullscreen
    if ('fullscreen' in document) {
        fullscreen = 'fullscreen' // W3C proposal
    } else if ('fullScreen' in document) {
        fullscreen = 'fullScreen' // mozilla proposal
    } else if ('webkitIsFullScreen' in document) {
        fullscreen = 'webkitIsFullScreen' // webkit
    } else if ('mozFullScreen' in document) {
        fullscreen = 'mozFullScreen' // firefox
    } else if ('msFullscreenElement' in document) {
        fullscreen = 'msFullscreenElement' // ms
    } else {
        fullscreen = null // not supported in this browser
    }

    if (document["webkitCancelFullScreen"]) {
        change = "webkitfullscreenchange";
        error = "webkitfullscreenerror";
    } else if (document["msExitFullscreen"]) {
        change = "MSFullscreenChange";
        error = "MSFullscreenError";
    } else if (document["mozCancelFullScreen"]) {
        change = "mozfullscreenchange";
        error = "mozfullscreenerror";
    } else {
        change = "fullscreenchange";
        error = "fullscreenerror";
    }

    return {
        enter: enter,
        exit: exit,
        fullscreen: fullscreen,
        change: change,
        error: error
    }
};

Wednesday, March 5, 2014

Use transients domain attributes with Grails

In latest versions of Grails, transient attributes are not binded with form by default. This is the documentation of the bindable constraint. This is how the code would become (you need to add bindable: true):


static transients = ['confirmarPassword'] 
static constraints = {
    password blank: false, password: true, size:5..15, matches:/[\S]+/
    confirmarPassword bindable: true, blank:false, password: true, size:5..15, matches:/[\S]+/, validator:{ val, obj ->
        if (obj.password != obj.confirmarPassword)
            return 'password.dontmatch'
    }
}

Sunday, March 2, 2014

Html element content change event

You could add some custom event to see effect change of the content of the element:
You can see this example here at jsFiddle: Html element content change event 
 

Html content


<table>
    <tr>
        <td valign="top">
           <button id="html">Click to see change 'html'.</button><br/>
           <button id="append">Click to see change 'append'.</button><br/>
           <button id="prepend">Click to see change 'prepend'.</button><br/>
           <div id="hello">This is text!</div>
        </td>
        <td valign="top">
            <div id="console"></div>
        </td>
    </tr>
</table>


jQuery content


// Redefines $.fn.html(), $.fn.append(), $.fn.prepend() to add custom events that are triggered before and after a DOM element's innerHtml is changed
// html-change-pre is triggered before the innerHtml is changed
// html-change-post is triggered after the innerHtml is changed

(function($) {
    var eventName = 'html-change';
    // Save a reference to the original html, append and prepend function
    $.fn.htmlx = $.fn.html;
    $.fn.appendx = $.fn.append;
    $.fn.prependx = $.fn.prepend;
    // Let's redefine the html, append and prepend function to include a custom event
    $.fn.html = function() {
        var currentHtml = this.htmlx();
        if(arguments.length) {
            this.trigger(eventName + '-pre', jQuery.merge([currentHtml], arguments));
            jQuery.fn.htmlx.apply(this, arguments);
            this.trigger(eventName + '-post', jQuery.merge([currentHtml], arguments));
            return this;
        } else {
            return currentHtml;
        }
    }
    $.fn.append = function() {
        var currentHtml = this.htmlx();
        if(arguments.length) {
            this.trigger(eventName + '-pre', jQuery.merge([currentHtml], arguments));
            jQuery.fn.appendx.apply(this, arguments);
            this.trigger(eventName + '-post', jQuery.merge([currentHtml], arguments));
            return this;
        } else {
            return currentHtml;
        }
    }
    $.fn.prepend = function() {
        var currentHtml = this.htmlx();
        if(arguments.length) {
            this.trigger(eventName + '-pre', jQuery.merge([currentHtml], arguments));
            jQuery.fn.prependx.apply(this, arguments);
            this.trigger(eventName + '-post', jQuery.merge([currentHtml], arguments));
            return this;
        } else {
            return currentHtml;
        }
    }
})(jQuery);
        
// Test
jQuery(document).ready(function() {

    jQuery('#hello').bind('html-change-pre', function() {
        $("#console").prepend('<div>html-change-pre triggered: '+counter+'</div>');
    });
    
    jQuery('#hello').bind('html-change-post', function() {
        $("#console").prepend('<div>html-change-post triggered: '+counter+'</div>');
    });
    var counter = 0;
    $("#html").click(function() {
        $("div#hello").html("<div>html: "+counter+"</div>");
        counter++;
    });
    $("#prepend").click(function() {
        $("div#hello").prepend("<div>prepend: "+counter+"</div>");
        counter++;
    });
    $("#append").click(function() {
        $("div#hello").append("<div>append: "+counter+"</div>");
        counter++;
    });
});

Example output at jsFiddle:


jQuery remove and restore element events

jsFiddle Link

function toggleEvent(id) {
    var target = $(id);
    var events = $._data(target[0], 'events');
    if(events!=undefined){    //  if the element has event || target = element
        target[0].event_name = [];
        target[0].event_handler = [];        
        $.each(events, function(event_name, event_handler) {
            target[0].event_name.push(event_name);
            var _handlers=[];
            for(var i=0;i<event_handler.length;i++){
                _handlers.push(event_handler[i].handler);
            }
            target[0].event_handler.push(_handlers);          
        });  //store the events
        target.off();  // delete the events
    }else{    // has the elment no event
        for(var i=0; i < target[0].event_handler.length; i++){
            for(var ii=0;ii<target[0].event_handler[i].length;ii++){
                target.on(target[0].event_name[i], target[0].event_handler[i][ii]);
            }          
        }  // re-store the events
        target[0].event_name = [];
        target[0].event_handler = [];  //reset
    }
}

$("#a").click(function() {
    alert("Event in action");
});

var eventInAction = true;
$("#b").click(function(){
    toggleEvent('#a');
    if(eventInAction) {
        eventInAction = false;
        $(this).html("Add events to button 'A'");
    } else {
        eventInAction = true;
        $(this).html("Remove events from button 'A'");
    }
});

Thursday, February 27, 2014

Binding a Grails date from params in a controller

Add the following lines in 'Config.groovy' file


grails.databinding.trimStrings=true
grails.databinding.convertEmptyStringsToNull=true
grails.databinding.dateFormats = ['yyyy-MM-dd HH:mm:ss.S', 'yyyy-MM-dd', "yyyy-MM-dd'T'hh:mm:ss'Z'"]

First line triming all string values on data binding to domain instance.
Second line convert all empty string to null.
And third line accept the date formats provided to convert it to date.

Or you can use those as following:


package com.pkm.test.domains

import org.grails.databinding.BindingFormat

class TestOne {
    Long id
    String name;
    String display;
    @BindingFormat("yyyy-mm-dd")
    Date created;

    static constraints = {
        display(nullable: true)
    }
}

And from controller


params.name = "YES-Pritom K Mondal";
params.display = " ";
params.created = "2014-02-27";
TestOne testOne = new TestOne();
DataBindingUtils.bindObjectToInstance(testOne, params)
testOne.save(failOnError: true);

Will create a following row in the table


Field 'display' is null because value from controller: ' ' first trim() and then convert empty string to null according to Config.groovy settings above.