blob: e6805f78ac5a0af5ec5df206f8c94e5bc3686b83 [file] [log] [blame]
/*
Copyright (c) 2007, Caridy Patiño. All rights reserved.
Portions Copyright (c) 2007, Yahoo!, Inc. All rights reserved.
Code licensed under the BSD License:
http://www.bubbling-library.com/eng/licence
version: 1.5.0
*/
YAHOO.namespace("plugin","behavior");
(function() {
var $Y = YAHOO.util,
$E = YAHOO.util.Event,
$D = YAHOO.util.Dom,
$L = YAHOO.lang,
$ = YAHOO.util.Dom.get;
/**
* @class Bubbling
*/
YAHOO.Bubbling = function () {
var obj = {},
ua = navigator.userAgent.toLowerCase(),
isOpera = (ua.indexOf('opera') > -1);
// private stuff
var navRelExternal = function (layer, args) {
var el = args[1].anchor;
if (!(args[1].flagged || args[1].decrepitate) && el) {
var r = el.getAttribute("rel"),
t = el.getAttribute("target");
if ((!t || (t === '')) && (r == 'external')) {
el.setAttribute("target", "blank");
}
}
};
var defaultActionsControl = function (layer, args) {
obj.processingAction (layer, args, obj.defaultActions);
};
var _searchYUIButton = function (t) {
var el = obj.getOwnerByClassName( t, 'yui-button' ), bt = null, id = null;
if ($L.isObject(el) && YAHOO.widget.Button) {
bt = YAHOO.widget.Button.getButton(el.id);
}
return bt;
};
// public vars
obj.ready = false;
obj.force2alfa = false;
obj.bubble = {}; // CustomEvent Handles
obj.onReady = new $Y.CustomEvent('bubblingOnReady', obj, true);
// mapping external methods...
obj.getOwnerByClassName = function(node, className) {
return ($D.hasClass(node, className)?node:$D.getAncestorByClassName (node, className));
};
obj.getOwnerByTagName = function(node, tagName) {
node = $D.get(node);
if (!node) {
return null;
}
return (node.tagName && node.tagName.toUpperCase() == tagName.toUpperCase()?node:$D.getAncestorByTagName (node, tagName));
};
// Deprecated in favor of getOwnerByClassName and getOwnerByTagName
obj.getAncestorByClassName = obj.getOwnerByClassName;
obj.getAncestorByTagName = obj.getOwnerByTagName;
// public methods
obj.onKeyPressedTrigger = function(args, e, m){
var b = 'key';
e = e || $E.getEvent();
m = m || {};
m.action = b;
m.target = args.target || (e?$E.getTarget(e):null);
m.flagged = false; m.decrepitate = false;
m.event = e;
m.stop = false;
m.type = args.type;
m.keyCode = args.keyCode;
m.charCode = args.charCode;
m.ctrlKey = args.ctrlKey;
m.shiftKey = args.shiftKey;
m.altKey = args.altKey;
this.bubble.key.fire(e, m);
if (m.stop) {
$E.stopEvent(e);
}
return m.stop;
};
obj.onEventTrigger = function(b, e, m){
e = e || $E.getEvent();
m = m || {};
m.action = b;
m.target = (e?$E.getTarget(e):null);
m.flagged = false; m.decrepitate = false;
m.event = e;
m.stop = false;
this.bubble[b].fire(e, m);
if (m.stop) {
$E.stopEvent(e);
}
return m.stop;
};
obj.onNavigate = function(e){
var conf = {
anchor: this.getOwnerByTagName( $E.getTarget(e), 'A' ),
button: _searchYUIButton($E.getTarget(e))
};
if (!conf.anchor && !conf.button) {
conf.input = this.getOwnerByTagName( $E.getTarget(e), 'INPUT' );
}
if (conf.button) {
conf.value = conf.button.get('value');
} else if (conf.input) {
conf.value = conf.input.getAttribute('value');
}
if (!this.onEventTrigger ('navigate', e, conf)) {
this.onEventTrigger ('god', e, conf); // if nobody claim the event, god can handle it...
}
};
obj.onProperty = function(e){
this.onEventTrigger ('property', e, {
anchor: this.getOwnerByTagName( $E.getTarget(e), 'A' ),
button: _searchYUIButton($E.getTarget(e))
});
};
obj._timeoutId = 0;
obj.onRepaint = function(e){
// Downshift Your Code (can’t let something happen multiple times in a second)
// http://yuiblog.com/blog/2007/07/09/downshift-your-code/
clearTimeout(obj._timeoutId);
obj._timeoutId = setTimeout(function(){
var b = 'repaint',
e = {target:document.body},
m = {
action: b,
target: null,
event: e,
flagged: false,
decrepitate: false,
stop: false
};
obj.bubble[b].fire(e, m);
if (m.stop) {
$E.stopEvent(e);
}
}, 150
);
};
obj.onRollOver = function(e){
this.onEventTrigger ('rollover', e, {
anchor: this.getOwnerByTagName( $E.getTarget(e), 'A' )
});
};
obj.onRollOut = function(e){
this.onEventTrigger ('rollout', e, {
anchor: this.getOwnerByTagName( $E.getTarget(e), 'A' )
});
};
obj.onKeyPressed = function(args){
this.onKeyPressedTrigger(args);
};
/**
* * Este método determina la acción por defecto para un elemento
* @public
* @param {object} el element reference
* @param {object} actions object with the list of posibles actions
* @return void
*/
obj.getActionName = function (el, depot) {
depot = depot || {};
var b = null, r = null,
f = ($D.inDocument(el)?function(b){return $D.hasClass(el, b)}:function(b){return el.hasClass(b);}); // f: check is certain object has a classname
if (el && ($L.isObject(el) || (el = $( el )))) {
try{
r = el.getAttribute("rel"); // if rel is available...
}catch(e){};
for (b in depot) { // behaviors in the depot...
if ((depot.hasOwnProperty(b)) && (f(b) || (b === r))) {
return b;
}
}
}
return null;
};
/**
* * Este método determina el primer tab hijo basado en el tabName
* @public
* @param {object} el Child element reference
* @param {object} c ClassName of the Ancestor
* @return void
*/
obj.getFirstChildByTagName = function (el, t) {
if (el && ($L.isObject(el) || (el = $( el ))) && t) {
var l = el.getElementsByTagName(t);
if (l.length > 0) {
return l[0];
}
}
return null;
};
/**
* * Este método determina si un evento es interno o no a un contenedor...
* @public
* @param {object} e Referencia al evento
* @param {object} el Referencia al contendor
* @return void
*/
obj.virtualTarget = function (e, el) {
if (el && ($L.isObject(el) || (el = $( el ))) && $L.isObject(e)) {
var t = $E.getRelatedTarget ( e ); // target element
if ($L.isObject(t)) {
while((t.parentNode) && $L.isObject(t.parentNode) && (t.parentNode.tagName !== "BODY")) {
if (t.parentNode === el) {
return true;
}
t = t.parentNode;
}
}
}
return false;
};
/**
* * Creating a new behaviors layer...
* @public
* @param {string||array} layers Behaviors layers GUID
* @param {object} scope Custom Event default execution scope
* @return boolean if not exists...
*/
obj.addLayer = function (layers, scope) {
var result = false;
layers = ($L.isArray(layers)?layers:[layers]);
scope = scope || window;
for (var i = 0; i < layers.length; ++i) {
if (layers[i] && !this.bubble.hasOwnProperty(layers[i])) {
this.bubble[layers[i]] = new $Y.CustomEvent(layers[i], scope, true);
result = true;
}
}
return result;
};
/**
* * Subcribing an bahavior to certain bahaviors layer...
* @public
* @param {string} layer Behavior layer GUID
* @param {object} bh The function that represent the behavior
* @return boolean if it is the first listener
*/
obj.subscribe = function (layer, bh, scope) {
var first = this.addLayer(layer); // return true if it's the first listener
if (layer) {
if ($L.isObject(scope)) {
this.bubble[layer].subscribe(bh, scope, true); // correcting the default scope
} else {
this.bubble[layer].subscribe(bh); // use the default scope
}
}
return first;
};
obj.on = obj.subscribe; // defining an alias...
/**
* * Broadcasting the message in the corresponding behavior layer...
* @public
* @param {string} layer Behavior layer GUID
* @param {object} obj The function that represent the behavior
* @return boolean if someone has claim the event
*/
obj.fire = function (layer, obj) {
obj = obj || {};
obj.action = layer;
obj.flagged = false; obj.decrepitate = false;
obj.stop = false;
if (this.bubble.hasOwnProperty(layer)) {
this.bubble[layer].fire(null, obj);
}
return obj.stop;
};
/**
* * Processing an action based on the classname of the target element...
* @public
* @param {string} layer Behavior layer GUID
* @param {object} args Event object (extended)
* @param {object} actions List of availables behaviors...
* @param {boolean} force Proccess the actions without worry about the flagged value...
* @return void
*/
obj.processingAction = function (layer, args, actions, force) {
var behavior = null, t;
if (!(args[1].flagged || args[1].decrepitate) || force) {
// checking for anchor, input or button
t = args[1].anchor || args[1].input || args[1].button;
if (t) {
behavior = this.getActionName ( t, actions );
args[1].el = t;
}
if (behavior && (actions[behavior].apply(args[1], [layer, args]))) {
$E.stopEvent(args[0]);
args[1].flagged = true;
args[1].decrepitate = true;
args[1].stop = true;
}
}
};
obj.defaultActions = {};
obj.addDefaultAction = function (n, f, force) {
if (n && f && (!this.defaultActions.hasOwnProperty(n) || force)) {
this.defaultActions[n] = f;
}
};
// default behaviors
$E.addListener(window, "resize", obj.onRepaint, obj, true);
// default Suscriptions
obj.on('navigate', navRelExternal);
obj.on('navigate', defaultActionsControl);
// initialization of the font and scroll monitors
obj.initMonitors = function ( config ) {
var fMonitors = function () {
var oMonitors = new YAHOO.widget.Module('yui-cms-font-monitor', {
monitorresize:true,
visible:false
});
oMonitors.render(document.body);
// monitoring font-size...
YAHOO.widget.Module.textResizeEvent.subscribe(obj.onRepaint, obj, true);
// monitoring scroll actions...
YAHOO.widget.Overlay.windowScrollEvent.subscribe(obj.onRepaint, obj, true);
};
if ($L.isFunction(YAHOO.widget.Module)) {
$E.onDOMReady (fMonitors, obj, true);
}
};
// initialization inside the selfconstructor
obj.init = function () {
if (!this.ready) {
var el = document.body;
$E.addListener(el,
"click",
obj.onNavigate,
obj,
true
);
/*
Listen for the "mousedown" event in Opera b/c it does not
support the "contextmenu" event
*/
$E.addListener(
el,
(isOpera ? "mousedown" : "contextmenu"),
obj.onProperty,
obj,
true
);
/*
Assign a "click" event handler to the trigger element(s) for
Opera to prevent default browser behaviors.
*/
if(isOpera) {
$E.addListener(
el,
"click",
obj.onProperty,
obj,
true
);
}
$E.addListener(el, "mouseover", obj.onRollOver, obj, true);
$E.addListener(el, "mouseout", obj.onRollOut, obj, true);
// keys...
$E.addListener(document, "keyup", obj.onKeyPressed, obj, true);
$E.addListener(document, "keydown", obj.onKeyPressed, obj, true);
this.ready = true;
obj.onReady.fire();
}
};
$E.onDOMReady(obj.init, obj, true);
// creating the default layers...
obj.addLayer (['navigate','god','property','key','repaint','rollover', 'rollout']); // god layer - hack: the layer after the common navigate layer...
return obj;
}();
})();
YAHOO.register("bubbling", YAHOO.Bubbling, {version: "1.5.0", build: "222"});