Bloggers recientes

Nate Cavanaugh

Staff
36 Mensajes
29 de agosto de 2014

Olaf Kock

Staff
78 Mensajes
26 de agosto de 2014

Matti Tahvonen

3 Mensajes
26 de agosto de 2014

Ronald Sarayudej

Staff
151 Mensajes
25 de agosto de 2014

James Falkner

Staff
95 Mensajes
25 de agosto de 2014

Paulo Fernandes

Staff
15 Mensajes
22 de agosto de 2014

Scott Lee

Staff
3 Mensajes
21 de agosto de 2014

Martin Yan

Staff
5 Mensajes
20 de agosto de 2014

Miguel Ángel Pastor Olivar

Staff
15 Mensajes
19 de agosto de 2014

Josiah "Duke" Harrist

Staff
1 Mensajes
13 de agosto de 2014
« Atrás

Hooking into Liferay's Javascript functions

Company Blogs 4 de febrero de 2008 Por Nate Cavanaugh Staff

Have you ever wanted to plugin to Liferay's javascript functions, but didn't want to modify the original Javascript, and didn't want to branch off of it? I know I have.

For instance, let's say that there is a Liferay javascript function that always adds a class, but you don't want to add that class, and instead want to use your own. Well, there is a little known method that does this that's in Liferay 4.3.x.

The method is called Liferay.Util.actsAsAspect. This little method adds AOP (aspect oriented programming) features, that allow you to hook into existing Javascript without a plugin framework being in place.

So, I'll use a good example of this. In Liferay, if you don't want the dock to be a drop down, you can go into dock.vm in your theme, and remove the class name of interactive-mode off of the main dock container.
This allows you to easily disable that feature.
But recently, we needed to remove this class, but didn't want to keep a floating copy of dock.vm where the only difference is one little class name.

So we could either modify the file anyways, or we could use Javascript to remove the class name. But then there become a race condition, where you're trying to race against the Dock javascript to remove the class before it can find the class and begin the transformation.

Well, that's where Liferay.Util.actsAsAspect comes in.

What it does is it takes the object you pass to it, and augments it to contain three new methods: before, after, and around.

So, in our case, we needed to modify Liferay.Dock (the class that creates the dock), and we needed a way to guarantee that the class name interactive-mode was removed, thereby preventing the Dock class from even seeing that there is a dock to modify.

So, here is what we did:

Liferay.Util.actsAsAspect(Liferay.Dock);

Liferay.Dock.before(
    'init',
    function(){
        jQuery('.interactive-mode').removeClass('interactive-mode');
    }
);

So, you see, now every time Liferay.Dock.init() runs, it will always execute our little function we passed into it first.

We can also run Javascript after, using Liferay.Dock.after() and passing in the name of our method, and a function we wish to execute.

We can also wrap the init function with code, like so:

Liferay.Dock.around(
'init',
function () {
    var dock = jQuery('.interactive-mode');
    dock.removeClass('interactive-mode');
   
    this.yield(); // This line executes the original function
   
    dock.addClass('interactive-mode'); // This line now adds the class back after the function fires
}
);

Now, the next question you may be asking is, how do you do this for classically defined functions (you know the ones that look something like: onLoad() or _88_updatePage()), and don't have a parent object that we can manipulate.

Well, we actually can manipulate because all functions defined like this: function _88_updatePage() {}, all exist inside of the "window" object. The "window" object is the global namespace where normal functions are added by default.

So, here is how we would execute a function before _88_updatePage get's executed:

Liferay.Util.actsAsAspect(window);

window.before(
'_88_updatePage',
function (month, day, year){
    alert('I am just about to update the page');
}
);

So, anyways, I thought that this would be helpful to people who need to hook into our existing Javascript, and can't wait till we implement our formal JS event system :)
 

Respuestas anidadas Autor Fecha
You can't even imagine how timely this post... Ray Augé 4 de febrero de 2008 14:06
ok! what if the methods has params... do I just... Ray Augé 4 de febrero de 2008 14:15
Yes sir :) Just like that. Nate Cavanaugh 4 de febrero de 2008 14:18
I have this: ... Ray Augé 4 de febrero de 2008 14:31
Yeah, sorry, I should have mentioned that. For... Nate Cavanaugh 4 de febrero de 2008 14:36
Yup, that works.. you rock Nate.. Ray Augé 4 de febrero de 2008 14:40
Hi, I'm using Liferay 6.0.5 and I used the your... Alexandra Mereuta 28 de octubre de 2010 9:03
I was pleasantly surprised that this post was... Barry Rowe 17 de mayo de 2011 13:12
The test. Hamidreza Soleimani 5 de febrero de 2008 3:52
Very very cool! Keep this type of post coming :) Jorge Ferrer 5 de febrero de 2008 3:55
Great post! Thanks Nate! Edward Shin 15 de febrero de 2008 14:30

You can't even imagine how timely this post was... I was about 2 minutes away from asking you how to best extend an existing function...

This is very clever...
Publicado el día 4/02/08 14:06.
ok! what if the methods has params... do I just cascade those down?

Liferay.Navigation.around(
'_removePage',
function (params) {
...
this.yield(params) ;
...
}
) ;
Publicado el día 4/02/08 14:15 en respuesta a Ray Auge.
Yes sir emoticon Just like that.
Publicado el día 4/02/08 14:18 en respuesta a Ray Auge.
I have this:

Liferay.Util.actsAsAspect(Liferay.Navigation);

Liferay.Navigation.around(
'_­removePage',
function (obj, instance) {
alert('test');
}
);

new Liferay.Navigation(
{
layoutIds: [<%= ListUtil.toString(layouts, "layoutId") %>],
navBlock: '#navigation',
hasPermission: <%= GroupPermissionUtil.contains(permissionChecker, portletGroupId.longValue(), ActionKeys.MANAGE_LAYOUTS) %>
}
);

this doesn't work... I'm doing something wrong aren't I?
Does an instance of an object need to be treated differently?
Publicado el día 4/02/08 14:31 en respuesta a Nate Cavanaugh.
Yeah, sorry, I should have mentioned that. For instantiable classes, you would modify that objects prototype, like so:

Liferay.Util.actsAsAspect(Liferay.Navigation.prototype);

Liferay.Navigation.pr­ototype.around(...)

That will also make sure that every instance of it will get your function with it.
Publicado el día 4/02/08 14:36 en respuesta a Ray Auge.
Yup, that works.. you rock Nate..
Publicado el día 4/02/08 14:40 en respuesta a Nate Cavanaugh.
Publicado el día 5/02/08 3:52.
Very very cool!

Keep this type of post coming emoticon
Publicado el día 5/02/08 3:55.
Great post! Thanks Nate!
Publicado el día 15/02/08 14:30.
Hi,
I'm using Liferay 6.0.5 and I used the your method to hook into some navigation javascript. The problem I have is that for IE8 I get this message: 'Liferay.Navigation.prototype' is null or not an object. Do you know what the problem might be?

Thanks
Publicado el día 28/10/10 9:03 en respuesta a Nate Cavanaugh.
I was pleasantly surprised that this post was still dead on for LR 6.0 EE SP1. The Example Ray was working through above was exactly what we needed to do. Our end result looks like so:

<aui:script position="inline" use="liferay-navigation">
Liferay.Util.actsAsAspect(Liferay.Navigation.prototype);
Liferay.Navigation.prototype.around('_removePage',
function(event){
alert('before');
//do your work here
this.yield(event);
alert('after');
//do more work here
});
</aui:script>
Publicado el día 17/05/11 13:12 en respuesta a Alexandra Mereuta.