After an update of PGadmin3 I was no longer able to
save empty passwords for servers. Therefore whenever I wanted to connect to a
server I had to click OK on the password dialog.
As this became annoying I found out that the only difference between my old
servers (without the need for a password dialog) and my new servers was in the
.pgpass
file in my home directory.
This file contains one saved password per line and follows the syntax:
hostname:port:database:username:password
So I quickly added two new lines for my newly added servers using *
for
database and leaving password empty and got rid of the password dialog.
When finally being able to
hook into the lifecycle of the gallery-node-accordion
module, I wanted to use events that other parts of the code could subscribe
to. That way I wouldn't need to hard-wire otherwise unrelated business logic.
My first approach was to fire custom events on the corresponding nodes of the accordion:
* accordion root fires accordion:ready
* accordion section fires accordion:item:open
and accordion:item:close
That way I would be able to subscribe to those events via Y, the accordion
root or the corresponding section. In order to benefit from event bubbling and
be able to subscribe in other parts of the code (with the same Y object) I
needed to publish the events for the corresponding nodes:
accordion.publish('accordion:ready', { fireOnce: true, emitFacade: true, broadcast: 1 });
accordion.all('.yui3-accordion-item').each(function(node) {
node.publish('accordion:item:open', { emitFacade: true, broadcast: 1 });
node.publish('accordion:item:close', { emitFacade: true, broadcast: 1 });
});
While I liked the concept and flexibility of firing those events on certain
nodes it turned out that there are certain limitations to that approach.
YUI().use('node', function(Y) {
Y.use('gallery-node-accordion', function() {
accordion.fire('accordion:ready');
});
Y.use('node', function() {
Y.on('accordion:ready', function(e) { ... }, '.yui3-accordion-item');
});
Y.use('io', function() {
Y.on('accordion:ready', function(e) { ... }, '.yui3-accordion-item');
});
});
In the above code the subscriber in Y.use('node')
triggers, but the
subscriber in Y.use('io')
does not. While in theory both should trigger
(broadcasting being enabled and both sharing the same Y instance), there seem
to be certain limitations to broadcasting events fired from a node. These
restrictions seem to be specific to certain modules and/or if they were
already loaded when the event is fired, but I don't fully understand the
design decision behind it.
The easy solution is to fire and subscribe to custom events on the Y instance
rather than using the specific nodes. You will loose the ability to limit your
event subscription to a specific accordion instance or item via generic
accordion:* events, but using application specific events will make your code
cleaner and easier to understand. So I introduced the events
people:accordion:ready
, people:section:open
and people:section:close
leading to the following code:
Y.use('gallery-node-accordion', function() {
Y.publish('people:accordion:ready', { fireOnce: true });
Y.publish('people:section:open');
Y.publish('people:section:close');
Y.fire('people:accordion:ready');
});
Y.use('node', function() {
Y.on('people:accordion:ready', function(e) { ... });
});
Y.use('io', function() {
Y.on('people:section:open', function(e) { ... });
Y.on('people:section:close', function(e) { ... });
});
At work we are using the
gallery-node-accordion
module from the YUI gallery to group content into sections. While the module
is quite useful to transform already existing content into an accordion
structure, it falls short on ways to hook into the accordion lifecycle. A
typical task might be to load ads when opening a section or scroll to the head
of the section once the accordion animation is complete. Normally you could
accomplish those hooks by firing events for those specific moments in the
accordion lifecycle and let users subscribe to those events to add business
logic. Unfortunately caridy (the developer of gallery-node-accordion) did only
leave todo comments instead of actually firing those events.
The proper solution would have been to fork caridys work from github, add
those events, post a pull request for caridy and point our application to use
my version of gallery-node-accordion
. I decided to take the easy option and
create a class that would inherit from Y.Plugin.NodeAccordion
and overwrite
the methods that I want to fire events for.
Y.namespace('Plugin').PeopleAccordion = Y.Base.create('PeopleAccordion', Y.Plugin.NodeAccordion, [], {
initializer: function(config) { ... },
_openItem: function(item) { ... }
}, { NS: 'accordion' });
It took me quite a while to get the above code working and have a functioning
Y.Plugin.PeopleAccordion
class that I could use. The main reason was that
although NodeAccordion
does already supply the static NS attribute it needs
to be supplied by PeopleAccordion
as well.
When using Y.Base.create
the initializer function is augmented with the one
from NodeAccordion
and therefore you can simply add your code and both
functions will be called. So the only thing left to do was firing an event in
_openItem
and forward the call to NodeAccordion._openItem
. After playing
around for another few hours I came to the conclusion that there is no way to
call the parents _openItem
method from the PeopleAccordion
instance. I was
able to get a prototype of NodeAccordion
and call (or apply) the _openItem
method, but as that method needs to operate on the instances attributes it was
no good.
I was at a dead end and had to resort to replacing the click event handlers in
PeopleAccordion
with my own.
node.plug(Y.Plugin.Accordion, { ... });
node.accordion._eventHandler.detach();
node.accordion._eventHandler = this.delegate('click', function(e) {
// custom code
node.accordion.toggleItem( e.target );
e.target.blur();
e.halt();
}, '.yui3-accordion-item-trigger');