first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,7 @@
.yui3-skin-night .yui3-widget-mask {
background-color: black;
zoom: 1;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=40)";
filter: alpha(opacity=40);
opacity: 0.4;
}
@@ -0,0 +1 @@
.yui3-skin-night .yui3-widget-mask{background-color:black;zoom:1;-ms-filter:"alpha(opacity=40)";filter:alpha(opacity=40);opacity:.4}#yui3-css-stamp.skin-night-widget-modality{display:none}
@@ -0,0 +1,7 @@
.yui3-skin-sam .yui3-widget-mask {
background-color: black;
zoom: 1;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=40)";
filter: alpha(opacity=40);
opacity: 0.4;
}
@@ -0,0 +1 @@
.yui3-skin-sam .yui3-widget-mask{background-color:black;zoom:1;-ms-filter:"alpha(opacity=40)";filter:alpha(opacity=40);opacity:.4}#yui3-css-stamp.skin-sam-widget-modality{display:none}
@@ -0,0 +1 @@
/* WidgetModality core styles */
@@ -0,0 +1,566 @@
YUI.add('widget-modality', function (Y, NAME) {
/**
* Provides modality support for Widgets, though an extension
*
* @module widget-modality
*/
var WIDGET = 'widget',
RENDER_UI = 'renderUI',
BIND_UI = 'bindUI',
SYNC_UI = 'syncUI',
BOUNDING_BOX = 'boundingBox',
VISIBLE = 'visible',
Z_INDEX = 'zIndex',
CHANGE = 'Change',
isBoolean = Y.Lang.isBoolean,
getCN = Y.ClassNameManager.getClassName,
MaskShow = "maskShow",
MaskHide = "maskHide",
ClickOutside = "clickoutside",
FocusOutside = "focusoutside",
supportsPosFixed = (function(){
/*! IS_POSITION_FIXED_SUPPORTED - Juriy Zaytsev (kangax) - http://yura.thinkweb2.com/cft/ */
var doc = Y.config.doc,
isSupported = null,
el, root;
if (doc.createElement) {
el = doc.createElement('div');
if (el && el.style) {
el.style.position = 'fixed';
el.style.top = '10px';
root = doc.body;
if (root && root.appendChild && root.removeChild) {
root.appendChild(el);
isSupported = (el.offsetTop === 10);
root.removeChild(el);
}
}
}
return isSupported;
}());
/**
* Widget extension, which can be used to add modality support to the base Widget class,
* through the Base.create method.
*
* @class WidgetModality
* @param {Object} config User configuration object
*/
function WidgetModal(config) {}
var MODAL = 'modal',
MASK = 'mask',
MODAL_CLASSES = {
modal : getCN(WIDGET, MODAL),
mask : getCN(WIDGET, MASK)
};
/**
* Static property used to define the default attribute
* configuration introduced by WidgetModality.
*
* @property ATTRS
* @static
* @type Object
*/
WidgetModal.ATTRS = {
/**
* @attribute maskNode
* @type Y.Node
*
* @description Returns a Y.Node instance of the node being used as the mask.
*/
maskNode : {
getter : '_getMaskNode',
readOnly : true
},
/**
* @attribute modal
* @type boolean
*
* @description Whether the widget should be modal or not.
*/
modal: {
value:false,
validator: isBoolean
},
/**
* @attribute focusOn
* @type array
*
* @description An array of objects corresponding to the nodes and events that will trigger a re-focus back on the widget.
* The implementer can supply an array of objects, with each object having the following properties:
* <p>eventName: (string, required): The eventName to listen to.</p>
* <p>node: (Y.Node, optional): The Y.Node that will fire the event (defaults to the boundingBox of the widget)</p>
* <p>By default, this attribute consists of two objects which will cause the widget to re-focus if anything
* outside the widget is clicked on or focussed upon.</p>
*/
focusOn: {
valueFn: function() {
return [
{
// node: this.get(BOUNDING_BOX),
eventName: ClickOutside
},
{
//node: this.get(BOUNDING_BOX),
eventName: FocusOutside
}
];
},
validator: Y.Lang.isArray
}
};
WidgetModal.CLASSES = MODAL_CLASSES;
WidgetModal._MASK = null;
/**
* Returns the mask if it exists on the page - otherwise creates a mask. There's only
* one mask on a page at a given time.
* <p>
* This method in invoked internally by the getter of the maskNode ATTR.
* </p>
* @method _GET_MASK
* @static
*/
WidgetModal._GET_MASK = function() {
var mask = WidgetModal._MASK,
win = Y.one('win');
if (mask && (mask.getDOMNode() !== null) && mask.inDoc()) {
return mask;
}
mask = Y.Node.create('<div></div>').addClass(MODAL_CLASSES.mask);
WidgetModal._MASK = mask;
if (supportsPosFixed) {
mask.setStyles({
position: 'fixed',
width : '100%',
height : '100%',
top : '0',
left : '0',
display : 'block'
});
} else {
mask.setStyles({
position: 'absolute',
width : win.get('winWidth') +'px',
height : win.get('winHeight') + 'px',
top : '0',
left : '0',
display : 'block'
});
}
return mask;
};
/**
* A stack of Y.Widget objects representing the current hierarchy of modal widgets presently displayed on the screen
* @property STACK
*/
WidgetModal.STACK = [];
WidgetModal.prototype = {
initializer: function () {
Y.after(this._renderUIModal, this, RENDER_UI);
Y.after(this._syncUIModal, this, SYNC_UI);
Y.after(this._bindUIModal, this, BIND_UI);
},
destructor: function () {
// Hack to remove this thing from the STACK.
this._uiSetHostVisibleModal(false);
},
// *** Instance Members *** //
_uiHandlesModal: null,
/**
* Adds modal class to the bounding box of the widget
* <p>
* This method in invoked after renderUI is invoked for the Widget class
* using YUI's aop infrastructure.
* </p>
* @method _renderUIModal
* @protected
*/
_renderUIModal : function () {
var bb = this.get(BOUNDING_BOX);
//cb = this.get(CONTENT_BOX);
//this makes the content box content appear over the mask
// cb.setStyles({
// position: ""
// });
this._repositionMask(this);
bb.addClass(MODAL_CLASSES.modal);
},
/**
* Hooks up methods to be executed when the widget's visibility or z-index changes
* <p>
* This method in invoked after bindUI is invoked for the Widget class
* using YUI's aop infrastructure.
* </p>
* @method _bindUIModal
* @protected
*/
_bindUIModal : function () {
this.after(VISIBLE+CHANGE, this._afterHostVisibleChangeModal);
this.after(Z_INDEX+CHANGE, this._afterHostZIndexChangeModal);
this.after("focusOnChange", this._afterFocusOnChange);
// Re-align the mask in the viewport if `position: fixed;` is not
// supported. iOS < 5 and Android < 3 don't actually support it even
// though they both pass the feature test; the UA sniff is here to
// account for that. Ideally this should be replaced with a better
// feature test.
if (!supportsPosFixed ||
(Y.UA.ios && Y.UA.ios < 5) ||
(Y.UA.android && Y.UA.android < 3)) {
Y.one('win').on('scroll', this._resyncMask, this);
}
},
/**
* Syncs the mask with the widget's current state, namely the visibility and z-index of the widget
* <p>
* This method in invoked after syncUI is invoked for the Widget class
* using YUI's aop infrastructure.
* </p>
* @method _syncUIModal
* @protected
*/
_syncUIModal : function () {
//var host = this.get(HOST);
this._uiSetHostVisibleModal(this.get(VISIBLE));
},
/**
* Provides mouse and tab focus to the widget's bounding box.
*
* @method _focus
*/
_focus : function () {
var bb = this.get(BOUNDING_BOX),
oldTI = bb.get('tabIndex');
bb.set('tabIndex', oldTI >= 0 ? oldTI : 0);
this.focus();
},
/**
* Blurs the widget.
*
* @method _blur
*/
_blur : function () {
this.blur();
},
/**
* Returns the Y.Node instance of the maskNode
*
* @method _getMaskNode
* @return {Node} The Y.Node instance of the mask, as returned from WidgetModal._GET_MASK
*/
_getMaskNode : function () {
return WidgetModal._GET_MASK();
},
/**
* Performs events attaching/detaching, stack shifting and mask repositioning based on the visibility of the widget
*
* @method _uiSetHostVisibleModal
* @param {boolean} Whether the widget is visible or not
*/
_uiSetHostVisibleModal : function (visible) {
var stack = WidgetModal.STACK,
maskNode = this.get('maskNode'),
isModal = this.get('modal'),
topModal, index;
if (visible) {
Y.Array.each(stack, function(modal){
modal._detachUIHandlesModal();
modal._blur();
});
// push on top of stack
stack.unshift(this);
this._repositionMask(this);
this._uiSetHostZIndexModal(this.get(Z_INDEX));
if (isModal) {
maskNode.show();
Y.later(1, this, '_attachUIHandlesModal');
this._focus();
}
} else {
index = Y.Array.indexOf(stack, this);
if (index >= 0) {
// Remove modal widget from global stack.
stack.splice(index, 1);
}
this._detachUIHandlesModal();
this._blur();
if (stack.length) {
topModal = stack[0];
this._repositionMask(topModal);
//topModal._attachUIHandlesModal();
topModal._uiSetHostZIndexModal(topModal.get(Z_INDEX));
if (topModal.get('modal')) {
//topModal._attachUIHandlesModal();
Y.later(1, topModal, '_attachUIHandlesModal');
topModal._focus();
}
} else {
if (maskNode.getStyle('display') === 'block') {
maskNode.hide();
}
}
}
},
/**
* Sets the z-index of the mask node.
*
* @method _uiSetHostZIndexModal
* @param {Number} Z-Index of the widget
*/
_uiSetHostZIndexModal : function (zIndex) {
if (this.get('modal')) {
this.get('maskNode').setStyle(Z_INDEX, zIndex || 0);
}
},
/**
* Attaches UI Listeners for "clickoutside" and "focusoutside" on the
* widget. When these events occur, and the widget is modal, focus is
* shifted back onto the widget.
*
* @method _attachUIHandlesModal
*/
_attachUIHandlesModal : function () {
if (this._uiHandlesModal || WidgetModal.STACK[0] !== this) {
// Quit early if we have ui handles, or if we not at the top
// of the global stack.
return;
}
var bb = this.get(BOUNDING_BOX),
maskNode = this.get('maskNode'),
focusOn = this.get('focusOn'),
focus = Y.bind(this._focus, this),
uiHandles = [],
i, len, o;
for (i = 0, len = focusOn.length; i < len; i++) {
o = {};
o.node = focusOn[i].node;
o.ev = focusOn[i].eventName;
o.keyCode = focusOn[i].keyCode;
//no keycode or node defined
if (!o.node && !o.keyCode && o.ev) {
uiHandles.push(bb.on(o.ev, focus));
}
//node defined, no keycode (not a keypress)
else if (o.node && !o.keyCode && o.ev) {
uiHandles.push(o.node.on(o.ev, focus));
}
//node defined, keycode defined, event defined (its a key press)
else if (o.node && o.keyCode && o.ev) {
uiHandles.push(o.node.on(o.ev, focus, o.keyCode));
}
else {
Y.log('focusOn ATTR Error: The event with name "'+o.ev+'" could not be attached.');
}
}
if ( ! supportsPosFixed) {
uiHandles.push(Y.one('win').on('scroll', Y.bind(function(){
maskNode.setStyle('top', maskNode.get('docScrollY'));
}, this)));
}
this._uiHandlesModal = uiHandles;
},
/**
* Detaches all UI Listeners that were set in _attachUIHandlesModal from the widget.
*
* @method _detachUIHandlesModal
*/
_detachUIHandlesModal : function () {
Y.each(this._uiHandlesModal, function(h){
h.detach();
});
this._uiHandlesModal = null;
},
/**
* Default function that is called when visibility is changed on the widget.
*
* @method _afterHostVisibleChangeModal
* @param {EventFacade} e The event facade of the change
*/
_afterHostVisibleChangeModal : function (e) {
this._uiSetHostVisibleModal(e.newVal);
},
/**
* Default function that is called when z-index is changed on the widget.
*
* @method _afterHostZIndexChangeModal
* @param {EventFacade} e The event facade of the change
*/
_afterHostZIndexChangeModal : function (e) {
this._uiSetHostZIndexModal(e.newVal);
},
/**
* Returns a boolean representing whether the current widget is in a "nested modality" state.
* This is done by checking the number of widgets currently on the stack.
*
* @method isNested
* @public
*/
isNested: function() {
var length = WidgetModal.STACK.length,
retval = (length > 1) ? true : false;
return retval;
},
/**
* Repositions the mask in the DOM for nested modality cases.
*
* @method _repositionMask
* @param {Widget} nextElem The Y.Widget instance that will be visible in the stack once the current widget is closed.
*/
_repositionMask: function(nextElem) {
var currentModal = this.get('modal'),
nextModal = nextElem.get('modal'),
maskNode = this.get('maskNode'),
bb, bbParent;
//if this is modal and host is not modal
if (currentModal && !nextModal) {
//leave the mask where it is, since the host is not modal.
maskNode.remove();
this.fire(MaskHide);
}
//if the main widget is not modal but the host is modal, or both of them are modal
else if ((!currentModal && nextModal) || (currentModal && nextModal)) {
//then remove the mask off DOM, reposition it, and reinsert it into the DOM
maskNode.remove();
this.fire(MaskHide);
bb = nextElem.get(BOUNDING_BOX);
bbParent = bb.get('parentNode') || Y.one('body');
bbParent.insert(maskNode, bbParent.get('firstChild'));
this.fire(MaskShow);
}
},
/**
* Resyncs the mask in the viewport for browsers that don't support fixed positioning
*
* @method _resyncMask
* @param {Y.Widget} nextElem The Y.Widget instance that will be visible in the stack once the current widget is closed.
* @private
*/
_resyncMask: function (e) {
var o = e.currentTarget,
offsetX = o.get('docScrollX'),
offsetY = o.get('docScrollY'),
w = o.get('innerWidth') || o.get('winWidth'),
h = o.get('innerHeight') || o.get('winHeight'),
mask = this.get('maskNode');
mask.setStyles({
"top": offsetY + "px",
"left": offsetX + "px",
"width": w + 'px',
"height": h + 'px'
});
},
/**
* Default function called when focusOn Attribute is changed. Remove existing listeners and create new listeners.
*
* @method _afterFocusOnChange
*/
_afterFocusOnChange : function() {
this._detachUIHandlesModal();
if (this.get(VISIBLE)) {
this._attachUIHandlesModal();
}
}
};
Y.WidgetModality = WidgetModal;
}, '3.18.1', {"requires": ["base-build", "event-outside", "widget"], "skinnable": true});
@@ -0,0 +1,3 @@
YUI.add("widget-modality",function(e,t){function g(e){}var n="widget",r="renderUI",i="bindUI",s="syncUI",o="boundingBox",u="visible",a="zIndex",f="Change",l=e.Lang.isBoolean,c=e.ClassNameManager.getClassName,h="maskShow",p="maskHide",d="clickoutside",v="focusoutside",m=function(){
/*! IS_POSITION_FIXED_SUPPORTED - Juriy Zaytsev (kangax) - http://yura.thinkweb2.com/cft/ */
;var t=e.config.doc,n=null,r,i;return t.createElement&&(r=t.createElement("div"),r&&r.style&&(r.style.position="fixed",r.style.top="10px",i=t.body,i&&i.appendChild&&i.removeChild&&(i.appendChild(r),n=r.offsetTop===10,i.removeChild(r)))),n}(),y="modal",b="mask",w={modal:c(n,y),mask:c(n,b)};g.ATTRS={maskNode:{getter:"_getMaskNode",readOnly:!0},modal:{value:!1,validator:l},focusOn:{valueFn:function(){return[{eventName:d},{eventName:v}]},validator:e.Lang.isArray}},g.CLASSES=w,g._MASK=null,g._GET_MASK=function(){var t=g._MASK,n=e.one("win");return t&&t.getDOMNode()!==null&&t.inDoc()?t:(t=e.Node.create("<div></div>").addClass(w.mask),g._MASK=t,m?t.setStyles({position:"fixed",width:"100%",height:"100%",top:"0",left:"0",display:"block"}):t.setStyles({position:"absolute",width:n.get("winWidth")+"px",height:n.get("winHeight")+"px",top:"0",left:"0",display:"block"}),t)},g.STACK=[],g.prototype={initializer:function(){e.after(this._renderUIModal,this,r),e.after(this._syncUIModal,this,s),e.after(this._bindUIModal,this,i)},destructor:function(){this._uiSetHostVisibleModal(!1)},_uiHandlesModal:null,_renderUIModal:function(){var e=this.get(o);this._repositionMask(this),e.addClass(w.modal)},_bindUIModal:function(){this.after(u+f,this._afterHostVisibleChangeModal),this.after(a+f,this._afterHostZIndexChangeModal),this.after("focusOnChange",this._afterFocusOnChange),(!m||e.UA.ios&&e.UA.ios<5||e.UA.android&&e.UA.android<3)&&e.one("win").on("scroll",this._resyncMask,this)},_syncUIModal:function(){this._uiSetHostVisibleModal(this.get(u))},_focus:function(){var e=this.get(o),t=e.get("tabIndex");e.set("tabIndex",t>=0?t:0),this.focus()},_blur:function(){this.blur()},_getMaskNode:function(){return g._GET_MASK()},_uiSetHostVisibleModal:function(t){var n=g.STACK,r=this.get("maskNode"),i=this.get("modal"),s,o;t?(e.Array.each(n,function(e){e._detachUIHandlesModal(),e._blur()}),n.unshift(this),this._repositionMask(this),this._uiSetHostZIndexModal(this.get(a)),i&&(r.show(),e.later(1,this,"_attachUIHandlesModal"),this._focus())):(o=e.Array.indexOf(n,this),o>=0&&n.splice(o,1),this._detachUIHandlesModal(),this._blur(),n.length?(s=n[0],this._repositionMask(s),s._uiSetHostZIndexModal(s.get(a)),s.get("modal")&&(e.later(1,s,"_attachUIHandlesModal"),s._focus())):r.getStyle("display")==="block"&&r.hide())},_uiSetHostZIndexModal:function(e){this.get("modal")&&this.get("maskNode").setStyle(a,e||0)},_attachUIHandlesModal:function(){if(this._uiHandlesModal||g.STACK[0]!==this)return;var t=this.get(o),n=this.get("maskNode"),r=this.get("focusOn"),i=e.bind(this._focus,this),s=[],u,a,f;for(u=0,a=r.length;u<a;u++)f={},f.node=r[u].node,f.ev=r[u].eventName,f.keyCode=r[u].keyCode,!f.node&&!f.keyCode&&f.ev?s.push(t.on(f.ev,i)):f.node&&!f.keyCode&&f.ev?s.push(f.node.on(f.ev,i)):f.node&&f.keyCode&&f.ev&&s.push(f.node.on(f.ev,i,f.keyCode));m||s.push(e.one("win").on("scroll",e.bind(function(){n.setStyle("top",n.get("docScrollY"))},this))),this._uiHandlesModal=s},_detachUIHandlesModal:function(){e.each(this._uiHandlesModal,function(e){e.detach()}),this._uiHandlesModal=null},_afterHostVisibleChangeModal:function(e){this._uiSetHostVisibleModal(e.newVal)},_afterHostZIndexChangeModal:function(e){this._uiSetHostZIndexModal(e.newVal)},isNested:function(){var e=g.STACK.length,t=e>1?!0:!1;return t},_repositionMask:function(t){var n=this.get("modal"),r=t.get("modal"),i=this.get("maskNode"),s,u;if(n&&!r)i.remove(),this.fire(p);else if(!n&&r||n&&r)i.remove(),this.fire(p),s=t.get(o),u=s.get("parentNode")||e.one("body"),u.insert(i,u.get("firstChild")),this.fire(h)},_resyncMask:function(e){var t=e.currentTarget,n=t.get("docScrollX"),r=t.get("docScrollY"),i=t.get("innerWidth")||t.get("winWidth"),s=t.get("innerHeight")||t.get("winHeight"),o=this.get("maskNode");o.setStyles({top:r+"px",left:n+"px",width:i+"px",height:s+"px"})},_afterFocusOnChange:function(){this._detachUIHandlesModal(),this.get(u)&&this._attachUIHandlesModal()}},e.WidgetModality=g},"3.18.1",{requires:["base-build","event-outside","widget"],skinnable:!0});
@@ -0,0 +1,565 @@
YUI.add('widget-modality', function (Y, NAME) {
/**
* Provides modality support for Widgets, though an extension
*
* @module widget-modality
*/
var WIDGET = 'widget',
RENDER_UI = 'renderUI',
BIND_UI = 'bindUI',
SYNC_UI = 'syncUI',
BOUNDING_BOX = 'boundingBox',
VISIBLE = 'visible',
Z_INDEX = 'zIndex',
CHANGE = 'Change',
isBoolean = Y.Lang.isBoolean,
getCN = Y.ClassNameManager.getClassName,
MaskShow = "maskShow",
MaskHide = "maskHide",
ClickOutside = "clickoutside",
FocusOutside = "focusoutside",
supportsPosFixed = (function(){
/*! IS_POSITION_FIXED_SUPPORTED - Juriy Zaytsev (kangax) - http://yura.thinkweb2.com/cft/ */
var doc = Y.config.doc,
isSupported = null,
el, root;
if (doc.createElement) {
el = doc.createElement('div');
if (el && el.style) {
el.style.position = 'fixed';
el.style.top = '10px';
root = doc.body;
if (root && root.appendChild && root.removeChild) {
root.appendChild(el);
isSupported = (el.offsetTop === 10);
root.removeChild(el);
}
}
}
return isSupported;
}());
/**
* Widget extension, which can be used to add modality support to the base Widget class,
* through the Base.create method.
*
* @class WidgetModality
* @param {Object} config User configuration object
*/
function WidgetModal(config) {}
var MODAL = 'modal',
MASK = 'mask',
MODAL_CLASSES = {
modal : getCN(WIDGET, MODAL),
mask : getCN(WIDGET, MASK)
};
/**
* Static property used to define the default attribute
* configuration introduced by WidgetModality.
*
* @property ATTRS
* @static
* @type Object
*/
WidgetModal.ATTRS = {
/**
* @attribute maskNode
* @type Y.Node
*
* @description Returns a Y.Node instance of the node being used as the mask.
*/
maskNode : {
getter : '_getMaskNode',
readOnly : true
},
/**
* @attribute modal
* @type boolean
*
* @description Whether the widget should be modal or not.
*/
modal: {
value:false,
validator: isBoolean
},
/**
* @attribute focusOn
* @type array
*
* @description An array of objects corresponding to the nodes and events that will trigger a re-focus back on the widget.
* The implementer can supply an array of objects, with each object having the following properties:
* <p>eventName: (string, required): The eventName to listen to.</p>
* <p>node: (Y.Node, optional): The Y.Node that will fire the event (defaults to the boundingBox of the widget)</p>
* <p>By default, this attribute consists of two objects which will cause the widget to re-focus if anything
* outside the widget is clicked on or focussed upon.</p>
*/
focusOn: {
valueFn: function() {
return [
{
// node: this.get(BOUNDING_BOX),
eventName: ClickOutside
},
{
//node: this.get(BOUNDING_BOX),
eventName: FocusOutside
}
];
},
validator: Y.Lang.isArray
}
};
WidgetModal.CLASSES = MODAL_CLASSES;
WidgetModal._MASK = null;
/**
* Returns the mask if it exists on the page - otherwise creates a mask. There's only
* one mask on a page at a given time.
* <p>
* This method in invoked internally by the getter of the maskNode ATTR.
* </p>
* @method _GET_MASK
* @static
*/
WidgetModal._GET_MASK = function() {
var mask = WidgetModal._MASK,
win = Y.one('win');
if (mask && (mask.getDOMNode() !== null) && mask.inDoc()) {
return mask;
}
mask = Y.Node.create('<div></div>').addClass(MODAL_CLASSES.mask);
WidgetModal._MASK = mask;
if (supportsPosFixed) {
mask.setStyles({
position: 'fixed',
width : '100%',
height : '100%',
top : '0',
left : '0',
display : 'block'
});
} else {
mask.setStyles({
position: 'absolute',
width : win.get('winWidth') +'px',
height : win.get('winHeight') + 'px',
top : '0',
left : '0',
display : 'block'
});
}
return mask;
};
/**
* A stack of Y.Widget objects representing the current hierarchy of modal widgets presently displayed on the screen
* @property STACK
*/
WidgetModal.STACK = [];
WidgetModal.prototype = {
initializer: function () {
Y.after(this._renderUIModal, this, RENDER_UI);
Y.after(this._syncUIModal, this, SYNC_UI);
Y.after(this._bindUIModal, this, BIND_UI);
},
destructor: function () {
// Hack to remove this thing from the STACK.
this._uiSetHostVisibleModal(false);
},
// *** Instance Members *** //
_uiHandlesModal: null,
/**
* Adds modal class to the bounding box of the widget
* <p>
* This method in invoked after renderUI is invoked for the Widget class
* using YUI's aop infrastructure.
* </p>
* @method _renderUIModal
* @protected
*/
_renderUIModal : function () {
var bb = this.get(BOUNDING_BOX);
//cb = this.get(CONTENT_BOX);
//this makes the content box content appear over the mask
// cb.setStyles({
// position: ""
// });
this._repositionMask(this);
bb.addClass(MODAL_CLASSES.modal);
},
/**
* Hooks up methods to be executed when the widget's visibility or z-index changes
* <p>
* This method in invoked after bindUI is invoked for the Widget class
* using YUI's aop infrastructure.
* </p>
* @method _bindUIModal
* @protected
*/
_bindUIModal : function () {
this.after(VISIBLE+CHANGE, this._afterHostVisibleChangeModal);
this.after(Z_INDEX+CHANGE, this._afterHostZIndexChangeModal);
this.after("focusOnChange", this._afterFocusOnChange);
// Re-align the mask in the viewport if `position: fixed;` is not
// supported. iOS < 5 and Android < 3 don't actually support it even
// though they both pass the feature test; the UA sniff is here to
// account for that. Ideally this should be replaced with a better
// feature test.
if (!supportsPosFixed ||
(Y.UA.ios && Y.UA.ios < 5) ||
(Y.UA.android && Y.UA.android < 3)) {
Y.one('win').on('scroll', this._resyncMask, this);
}
},
/**
* Syncs the mask with the widget's current state, namely the visibility and z-index of the widget
* <p>
* This method in invoked after syncUI is invoked for the Widget class
* using YUI's aop infrastructure.
* </p>
* @method _syncUIModal
* @protected
*/
_syncUIModal : function () {
//var host = this.get(HOST);
this._uiSetHostVisibleModal(this.get(VISIBLE));
},
/**
* Provides mouse and tab focus to the widget's bounding box.
*
* @method _focus
*/
_focus : function () {
var bb = this.get(BOUNDING_BOX),
oldTI = bb.get('tabIndex');
bb.set('tabIndex', oldTI >= 0 ? oldTI : 0);
this.focus();
},
/**
* Blurs the widget.
*
* @method _blur
*/
_blur : function () {
this.blur();
},
/**
* Returns the Y.Node instance of the maskNode
*
* @method _getMaskNode
* @return {Node} The Y.Node instance of the mask, as returned from WidgetModal._GET_MASK
*/
_getMaskNode : function () {
return WidgetModal._GET_MASK();
},
/**
* Performs events attaching/detaching, stack shifting and mask repositioning based on the visibility of the widget
*
* @method _uiSetHostVisibleModal
* @param {boolean} Whether the widget is visible or not
*/
_uiSetHostVisibleModal : function (visible) {
var stack = WidgetModal.STACK,
maskNode = this.get('maskNode'),
isModal = this.get('modal'),
topModal, index;
if (visible) {
Y.Array.each(stack, function(modal){
modal._detachUIHandlesModal();
modal._blur();
});
// push on top of stack
stack.unshift(this);
this._repositionMask(this);
this._uiSetHostZIndexModal(this.get(Z_INDEX));
if (isModal) {
maskNode.show();
Y.later(1, this, '_attachUIHandlesModal');
this._focus();
}
} else {
index = Y.Array.indexOf(stack, this);
if (index >= 0) {
// Remove modal widget from global stack.
stack.splice(index, 1);
}
this._detachUIHandlesModal();
this._blur();
if (stack.length) {
topModal = stack[0];
this._repositionMask(topModal);
//topModal._attachUIHandlesModal();
topModal._uiSetHostZIndexModal(topModal.get(Z_INDEX));
if (topModal.get('modal')) {
//topModal._attachUIHandlesModal();
Y.later(1, topModal, '_attachUIHandlesModal');
topModal._focus();
}
} else {
if (maskNode.getStyle('display') === 'block') {
maskNode.hide();
}
}
}
},
/**
* Sets the z-index of the mask node.
*
* @method _uiSetHostZIndexModal
* @param {Number} Z-Index of the widget
*/
_uiSetHostZIndexModal : function (zIndex) {
if (this.get('modal')) {
this.get('maskNode').setStyle(Z_INDEX, zIndex || 0);
}
},
/**
* Attaches UI Listeners for "clickoutside" and "focusoutside" on the
* widget. When these events occur, and the widget is modal, focus is
* shifted back onto the widget.
*
* @method _attachUIHandlesModal
*/
_attachUIHandlesModal : function () {
if (this._uiHandlesModal || WidgetModal.STACK[0] !== this) {
// Quit early if we have ui handles, or if we not at the top
// of the global stack.
return;
}
var bb = this.get(BOUNDING_BOX),
maskNode = this.get('maskNode'),
focusOn = this.get('focusOn'),
focus = Y.bind(this._focus, this),
uiHandles = [],
i, len, o;
for (i = 0, len = focusOn.length; i < len; i++) {
o = {};
o.node = focusOn[i].node;
o.ev = focusOn[i].eventName;
o.keyCode = focusOn[i].keyCode;
//no keycode or node defined
if (!o.node && !o.keyCode && o.ev) {
uiHandles.push(bb.on(o.ev, focus));
}
//node defined, no keycode (not a keypress)
else if (o.node && !o.keyCode && o.ev) {
uiHandles.push(o.node.on(o.ev, focus));
}
//node defined, keycode defined, event defined (its a key press)
else if (o.node && o.keyCode && o.ev) {
uiHandles.push(o.node.on(o.ev, focus, o.keyCode));
}
else {
}
}
if ( ! supportsPosFixed) {
uiHandles.push(Y.one('win').on('scroll', Y.bind(function(){
maskNode.setStyle('top', maskNode.get('docScrollY'));
}, this)));
}
this._uiHandlesModal = uiHandles;
},
/**
* Detaches all UI Listeners that were set in _attachUIHandlesModal from the widget.
*
* @method _detachUIHandlesModal
*/
_detachUIHandlesModal : function () {
Y.each(this._uiHandlesModal, function(h){
h.detach();
});
this._uiHandlesModal = null;
},
/**
* Default function that is called when visibility is changed on the widget.
*
* @method _afterHostVisibleChangeModal
* @param {EventFacade} e The event facade of the change
*/
_afterHostVisibleChangeModal : function (e) {
this._uiSetHostVisibleModal(e.newVal);
},
/**
* Default function that is called when z-index is changed on the widget.
*
* @method _afterHostZIndexChangeModal
* @param {EventFacade} e The event facade of the change
*/
_afterHostZIndexChangeModal : function (e) {
this._uiSetHostZIndexModal(e.newVal);
},
/**
* Returns a boolean representing whether the current widget is in a "nested modality" state.
* This is done by checking the number of widgets currently on the stack.
*
* @method isNested
* @public
*/
isNested: function() {
var length = WidgetModal.STACK.length,
retval = (length > 1) ? true : false;
return retval;
},
/**
* Repositions the mask in the DOM for nested modality cases.
*
* @method _repositionMask
* @param {Widget} nextElem The Y.Widget instance that will be visible in the stack once the current widget is closed.
*/
_repositionMask: function(nextElem) {
var currentModal = this.get('modal'),
nextModal = nextElem.get('modal'),
maskNode = this.get('maskNode'),
bb, bbParent;
//if this is modal and host is not modal
if (currentModal && !nextModal) {
//leave the mask where it is, since the host is not modal.
maskNode.remove();
this.fire(MaskHide);
}
//if the main widget is not modal but the host is modal, or both of them are modal
else if ((!currentModal && nextModal) || (currentModal && nextModal)) {
//then remove the mask off DOM, reposition it, and reinsert it into the DOM
maskNode.remove();
this.fire(MaskHide);
bb = nextElem.get(BOUNDING_BOX);
bbParent = bb.get('parentNode') || Y.one('body');
bbParent.insert(maskNode, bbParent.get('firstChild'));
this.fire(MaskShow);
}
},
/**
* Resyncs the mask in the viewport for browsers that don't support fixed positioning
*
* @method _resyncMask
* @param {Y.Widget} nextElem The Y.Widget instance that will be visible in the stack once the current widget is closed.
* @private
*/
_resyncMask: function (e) {
var o = e.currentTarget,
offsetX = o.get('docScrollX'),
offsetY = o.get('docScrollY'),
w = o.get('innerWidth') || o.get('winWidth'),
h = o.get('innerHeight') || o.get('winHeight'),
mask = this.get('maskNode');
mask.setStyles({
"top": offsetY + "px",
"left": offsetX + "px",
"width": w + 'px',
"height": h + 'px'
});
},
/**
* Default function called when focusOn Attribute is changed. Remove existing listeners and create new listeners.
*
* @method _afterFocusOnChange
*/
_afterFocusOnChange : function() {
this._detachUIHandlesModal();
if (this.get(VISIBLE)) {
this._attachUIHandlesModal();
}
}
};
Y.WidgetModality = WidgetModal;
}, '3.18.1', {"requires": ["base-build", "event-outside", "widget"], "skinnable": true});