From: Alan Knowles Date: Mon, 7 Jun 2021 07:27:59 +0000 (+0800) Subject: menu position calcs based on align X-Git-Url: http://git.roojs.org/?p=roojs1;a=commitdiff_plain;h=fe420d2446bbf077df23ab1ce3159fe2cd786415 menu position calcs based on align --- diff --git a/Roo/bootstrap/Menu.js b/Roo/bootstrap/Menu.js index a1e7f54446..d396fa3ce1 100644 --- a/Roo/bootstrap/Menu.js +++ b/Roo/bootstrap/Menu.js @@ -13,8 +13,9 @@ * @cfg {bool} hidden if the menu should be hidden when rendered. * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true) * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false) - * @cfg {bool} hideTrigger (true|false) default false - hide the carret for trigger. - * + * @cfg {bool} hideTrigger (true|false) default false - hide the carret for trigger. + * @cfg {String} align default tl-bl? == below - how the menu should be aligned. + * @constructor * Create a new Menu * @param {Object} config The config object @@ -91,7 +92,7 @@ Roo.bootstrap.Menu = function(config){ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { /// html : false, - //align : '', + triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()??? type: false, /** @@ -113,6 +114,8 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { hideTrigger : false, + align : 'tl-bl?', + getChildContainer : function() { return this.el; @@ -123,8 +126,7 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { //if (['right'].indexOf(this.align)!==-1) { // cfg.cn[1].cls += ' pull-right' //} - - + var cfg = { tag : 'ul', cls : 'dropdown-menu shadow' , @@ -275,8 +277,31 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { if(!this.el){ this.render(); } + this.el.addClass('show'); // show otherwise we do not know how big we are.. + + var xy = this.el.getAlignToXY(el, pos); + + // bl-tl << left align below + // tl-bl << left align + + if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){ + // if it goes to far to the right.. -> align left. + xy = this.el.getAlignToXY(el, this.align.replace('/l/g', 'r')) + } + if(xy[0] < 0){ + // was left align - go right? + xy = this.el.getAlignToXY(el, this.align.replace('/r/g', 'l')) + } + + // goes down the bottom + if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight() || + xy[1] < 0 ){ + var a = this.align.replace('?', '').split('-'); + xy = this.el.getAlignToXY(el, a[1] + '-' + a[0] + '?') + + } - this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false); + this.showAt( xy , parentMenu, false); }, /** * Displays this menu at a specific xy position @@ -299,15 +324,11 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { this.triggerEl.addClass('open'); this.el.addClass('show'); + + // reassign x when hitting right - if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){ - xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth(); - } // reassign y when hitting bottom - if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){ - xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight(); - } // but the list may align on trigger left or trigger top... should it be a properity? @@ -395,7 +416,8 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { this.hide(); } else { Roo.log('show'); - this.show(this.triggerEl, '?', false); + + this.show(this.triggerEl, this.align, false); } if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){ diff --git a/roojs-bootstrap-debug.js b/roojs-bootstrap-debug.js index 20515d5da2..6dff3ac4d0 100644 --- a/roojs-bootstrap-debug.js +++ b/roojs-bootstrap-debug.js @@ -3579,8 +3579,9 @@ Roo.bootstrap.MenuMgr = function(){ * @cfg {bool} hidden if the menu should be hidden when rendered. * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true) * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false) - * @cfg {bool} hideTrigger (true|false) default false - hide the carret for trigger. - * + * @cfg {bool} hideTrigger (true|false) default false - hide the carret for trigger. + * @cfg {String} align default tl-bl? == below - how the menu should be aligned. + * @constructor * Create a new Menu * @param {Object} config The config object @@ -3657,7 +3658,7 @@ Roo.bootstrap.Menu = function(config){ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { /// html : false, - //align : '', + triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()??? type: false, /** @@ -3679,6 +3680,8 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { hideTrigger : false, + align : 'tl-bl?', + getChildContainer : function() { return this.el; @@ -3689,8 +3692,7 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { //if (['right'].indexOf(this.align)!==-1) { // cfg.cn[1].cls += ' pull-right' //} - - + var cfg = { tag : 'ul', cls : 'dropdown-menu shadow' , @@ -3841,8 +3843,31 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { if(!this.el){ this.render(); } + this.el.addClass('show'); // show otherwise we do not know how big we are.. + + var xy = this.el.getAlignToXY(el, pos); + + // bl-tl << left align below + // tl-bl << left align + + if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){ + // if it goes to far to the right.. -> align left. + xy = this.el.getAlignToXY(el, this.align.replace('/l/g', 'r')) + } + if(xy[0] < 0){ + // was left align - go right? + xy = this.el.getAlignToXY(el, this.align.replace('/r/g', 'l')) + } + + // goes down the bottom + if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight() || + xy[1] < 0 ){ + var a = this.align.replace('?', '').split('-'); + xy = this.el.getAlignToXY(el, a[1] + '-' + a[0] + '?') + + } - this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false); + this.showAt( xy , parentMenu, false); }, /** * Displays this menu at a specific xy position @@ -3865,15 +3890,11 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { this.triggerEl.addClass('open'); this.el.addClass('show'); + + // reassign x when hitting right - if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){ - xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth(); - } // reassign y when hitting bottom - if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){ - xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight(); - } // but the list may align on trigger left or trigger top... should it be a properity? @@ -3961,7 +3982,8 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, { this.hide(); } else { Roo.log('show'); - this.show(this.triggerEl, '?', false); + + this.show(this.triggerEl, this.align, false); } if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){ diff --git a/roojs-bootstrap.js b/roojs-bootstrap.js index 4f571c17a5..c4ff2bd321 100644 --- a/roojs-bootstrap.js +++ b/roojs-bootstrap.js @@ -153,21 +153,22 @@ F.un("show",onShow);var g=F.group;if(g&&F.events["checkchange"]){C[g].remove(F); if(g){C[g].remove(F);F.un("beforecheckchange",onBeforeCheck);}}};}(); // Roo/bootstrap/Menu.js Roo.bootstrap.Menu=function(A){Roo.bootstrap.Menu.superclass.constructor.call(this,A);if(this.registerMenu&&this.type!='treeview'){Roo.bootstrap.MenuMgr.register(this);}this.addEvents({beforeshow:true,beforehide:true,show:true,hide:true,click:true,mouseover:true,mouseout:true,itemclick:true} -);this.menuitems=new Roo.util.MixedCollection(false,function(o){return o.el.id;});};Roo.extend(Roo.bootstrap.Menu,Roo.bootstrap.Component,{triggerEl:false,type:false,registerMenu:true,menuItems:false,hidden:true,parentMenu:false,stopEvent:true,isLink:false,container_method:'getDocumentBody',hideTrigger:false,getChildContainer:function(){return this.el; +);this.menuitems=new Roo.util.MixedCollection(false,function(o){return o.el.id;});};Roo.extend(Roo.bootstrap.Menu,Roo.bootstrap.Component,{triggerEl:false,type:false,registerMenu:true,menuItems:false,hidden:true,parentMenu:false,stopEvent:true,isLink:false,container_method:'getDocumentBody',hideTrigger:false,align:'tl-bl?',getChildContainer:function(){return this.el; },getAutoCreate:function(){var A={tag:'ul',cls:'dropdown-menu shadow',style:'z-index:1000'};if(this.type==='submenu'){A.cls='submenu active';}if(this.type==='treeview'){A.cls='treeview-menu';}return A;},initEvents:function(){this.triggerEl.on('click',this.onTriggerClick,this); this.triggerEl.on(Roo.isTouch?'touchstart':'mouseup',this.onTriggerPress,this);if(!this.hideTrigger){if(this.triggerEl.hasClass('nav-item')&&this.triggerEl.select('.nav-link',true).length){this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle'); }else{this.triggerEl.addClass('dropdown-toggle');}}if(Roo.isTouch){this.el.on('touchstart',this.onTouch,this);}this.el.on('click',this.onClick,this);this.el.on("mouseover",this.onMouseOver,this);this.el.on("mouseout",this.onMouseOut,this);},findTargetItem:function(e){var t=e.getTarget(".dropdown-menu-item",this.el,true); if(!t){return false;}if(t&&t.id){return this.menuitems.get(t.id);}return false;},onTouch:function(e){Roo.log("menu.onTouch");this.onClick(e);},onClick:function(e){Roo.log("menu.onClick");var t=this.findTargetItem(e);if(!t||t.isContainer){return;}Roo.log(e); Roo.log('pass click event');t.onClick(e);this.fireEvent("click",this,t,e);var A=this;if(!t.href.length||t.href=='#'){(function(){A.hide();}).defer(100);}},onMouseOver:function(e){var t=this.findTargetItem(e);this.fireEvent("mouseover",this,e,t);},isVisible:function(){return !this.hidden; -},onMouseOut:function(e){var t=this.findTargetItem(e);this.fireEvent("mouseout",this,e,t);},show:function(el,A,B){if(false===this.fireEvent("beforeshow",this)){Roo.log("show canceled");return;}this.parentMenu=B;if(!this.el){this.render();}this.showAt(this.el.getAlignToXY(el,A||this.defaultAlign),B,false); -},showAt:function(xy,A,_e){this.parentMenu=A;if(!this.el){this.render();}if(_e!==false){this.fireEvent("beforeshow",this);}this.hideMenuItems();this.hidden=false;this.triggerEl.addClass('open');this.el.addClass('show');if(this.el.getWidth()+xy[0]>=Roo.lib.Dom.getViewWidth()){xy[0]=xy[0]-this.el.getWidth()+this.triggerEl.getWidth(); -}if(this.el.getHeight()+xy[1]>=Roo.lib.Dom.getViewHeight()){xy[1]=xy[1]-this.el.getHeight()-this.triggerEl.getHeight();}if(this.el.getStyle('top')!='auto'&&this.el.getStyle('top').slice(-1)!="%"){this.el.setXY(xy);}this.focus();this.fireEvent("show",this); -},focus:function(){return;if(!this.hidden){this.doFocus.defer(50,this);}},doFocus:function(){if(!this.hidden){this.focusEl.focus();}},hide:function(A){if(false===this.fireEvent("beforehide",this)){Roo.log("hide canceled");return;}this.hideMenuItems();if(this.el&&this.isVisible()){if(this.activeItem){this.activeItem.deactivate(); -this.activeItem=null;}this.triggerEl.removeClass('open');;this.el.removeClass('show');this.hidden=true;this.fireEvent("hide",this);}if(A===true&&this.parentMenu){this.parentMenu.hide(true);}},onTriggerClick:function(e){Roo.log('trigger click');var A=e.getTarget(); -Roo.log(A.nodeName.toLowerCase());if(A.nodeName.toLowerCase()==='i'){e.preventDefault();}},onTriggerPress:function(e){Roo.log('trigger press');var A=Roo.get(e.getTarget());if(A.findParent('.dropdown-menu')||A.findParent('.treeview-menu')){Roo.log('is treeview or dropdown?'); -return;}if(e.getTarget().nodeName.toLowerCase()!=='i'&&this.isLink){return;}if(this.isVisible()){Roo.log('hide');this.hide();}else{Roo.log('show');this.show(this.triggerEl,'?',false);}if(this.stopEvent||e.getTarget().nodeName.toLowerCase()==='i'){e.stopEvent(); -}},hideMenuItems:function(){Roo.log("hide Menu Items");if(!this.el){return;}this.el.select('.open',true).each(function(aa){aa.removeClass('open');});},addxtypeChild:function(A,B){var C=Roo.bootstrap.Menu.superclass.addxtypeChild.call(this,A,B);this.menuitems.add(C); -return C;},getEl:function(){Roo.log(this.el);return this.el;},clear:function(){this.getEl().dom.innerHTML='';this.menuitems.clear();}}); +},onMouseOut:function(e){var t=this.findTargetItem(e);this.fireEvent("mouseout",this,e,t);},show:function(el,A,B){if(false===this.fireEvent("beforeshow",this)){Roo.log("show canceled");return;}this.parentMenu=B;if(!this.el){this.render();}this.el.addClass('show'); +var xy=this.el.getAlignToXY(el,A);if(this.el.getWidth()+xy[0]>=Roo.lib.Dom.getViewWidth()){xy=this.el.getAlignToXY(el,this.align.replace('/l/g','r'))}if(xy[0]<0){xy=this.el.getAlignToXY(el,this.align.replace('/r/g','l'))}if(this.el.getHeight()+xy[1]>=Roo.lib.Dom.getViewHeight()||xy[1]<0){var a=this.align.replace('?','').split('-'); +xy=this.el.getAlignToXY(el,a[1]+'-'+a[0]+'?')}this.showAt(xy,B,false);},showAt:function(xy,A,_e){this.parentMenu=A;if(!this.el){this.render();}if(_e!==false){this.fireEvent("beforeshow",this);}this.hideMenuItems();this.hidden=false;this.triggerEl.addClass('open'); +this.el.addClass('show');if(this.el.getStyle('top')!='auto'&&this.el.getStyle('top').slice(-1)!="%"){this.el.setXY(xy);}this.focus();this.fireEvent("show",this);},focus:function(){return;if(!this.hidden){this.doFocus.defer(50,this);}},doFocus:function(){if(!this.hidden){this.focusEl.focus(); +}},hide:function(A){if(false===this.fireEvent("beforehide",this)){Roo.log("hide canceled");return;}this.hideMenuItems();if(this.el&&this.isVisible()){if(this.activeItem){this.activeItem.deactivate();this.activeItem=null;}this.triggerEl.removeClass('open'); +;this.el.removeClass('show');this.hidden=true;this.fireEvent("hide",this);}if(A===true&&this.parentMenu){this.parentMenu.hide(true);}},onTriggerClick:function(e){Roo.log('trigger click');var A=e.getTarget();Roo.log(A.nodeName.toLowerCase());if(A.nodeName.toLowerCase()==='i'){e.preventDefault(); +}},onTriggerPress:function(e){Roo.log('trigger press');var A=Roo.get(e.getTarget());if(A.findParent('.dropdown-menu')||A.findParent('.treeview-menu')){Roo.log('is treeview or dropdown?');return;}if(e.getTarget().nodeName.toLowerCase()!=='i'&&this.isLink){return; +}if(this.isVisible()){Roo.log('hide');this.hide();}else{Roo.log('show');this.show(this.triggerEl,this.align,false);}if(this.stopEvent||e.getTarget().nodeName.toLowerCase()==='i'){e.stopEvent();}},hideMenuItems:function(){Roo.log("hide Menu Items");if(!this.el){return; +}this.el.select('.open',true).each(function(aa){aa.removeClass('open');});},addxtypeChild:function(A,B){var C=Roo.bootstrap.Menu.superclass.addxtypeChild.call(this,A,B);this.menuitems.add(C);return C;},getEl:function(){Roo.log(this.el);return this.el;},clear:function(){this.getEl().dom.innerHTML=''; +this.menuitems.clear();}}); // Roo/bootstrap/MenuItem.js Roo.bootstrap.MenuItem=function(A){Roo.bootstrap.MenuItem.superclass.constructor.call(this,A);this.addEvents({"click":true});};Roo.extend(Roo.bootstrap.MenuItem,Roo.bootstrap.Component,{href:false,html:false,preventDefault:false,isContainer:false,active:false,fa:false,getAutoCreate:function(){if(this.isContainer){return {tag:'li',cls:'dropdown-menu-item '} ;}var A={tag:'span',html:'Link'};var B={tag:'a',cls:'dropdown-item',href:'#',cn:[]};if(this.fa!==false){B.cn.push({tag:'i',cls:'fa fa-'+this.fa});}B.cn.push(A);var C={tag:'li',cls:'dropdown-menu-item',cn:[B]};if(this.parent().type=='treeview'){C.cls='treeview-menu';