UNPKG

ares-ide

Version:

A browser-based code editor and UI designer for Enyo 2 projects

194 lines (183 loc) 6.72 kB
/** _onyx.Menu_ is a subkind of [onyx.Popup](#onyx.Popup) that displays a list of [onyx.MenuItem](#onyx.MenuItem") objects and looks like a popup menu. It is meant to be used together with an [onyx.MenuDecorator](#onyx.MenuDecorator). The decorator couples the menu with an activating control, which may be a button or any other control with an _onActivate_ event. When the control is activated, the menu shows itself in the correct position relative to the activator. {kind: "onyx.MenuDecorator", components: [ {content: "Show menu"}, {kind: "onyx.Menu", components: [ {content: "1"}, {content: "2"}, {classes: "onyx-menu-divider"}, {content: "Label", classes: "onyx-menu-label"}, {content: "3"}, ]} ]} For more information, see the documentation on [Menus](building-apps/controls/menus.html) in the Enyo Developer Guide. */ enyo.kind({ name: "onyx.Menu", kind: "onyx.Popup", //* If true, prevents controls outside the menu from receiving events while //* the menu is showing modal: true, defaultKind: "onyx.MenuItem", classes: "onyx-menu", published: { //* Maximum height of the menu maxHeight: 200, //* Toggle scrolling scrolling: true, //* Scroll strategy scrollStrategyKind: "TouchScrollStrategy" }, handlers: { onActivate: "itemActivated", onRequestShowMenu: "requestMenuShow", onRequestHideMenu: "requestHide" }, childComponents: [ {name: "client", kind: "enyo.Scroller"} ], showOnTop: false, scrollerName: "client", create: function() { this.inherited(arguments); this.maxHeightChanged(); }, initComponents: function() { if (this.scrolling) { this.createComponents(this.childComponents, {isChrome: true, strategyKind: this.scrollStrategyKind}); } this.inherited(arguments); }, getScroller: function() { return this.$[this.scrollerName]; }, maxHeightChanged: function() { if (this.scrolling) { this.getScroller().setMaxHeight(this.maxHeight + "px"); } }, itemActivated: function(inSender, inEvent) { inEvent.originator.setActive(false); return true; }, showingChanged: function() { this.inherited(arguments); if (this.scrolling) { this.getScroller().setShowing(this.showing); } this.adjustPosition(true); }, requestMenuShow: function(inSender, inEvent) { if (this.floating) { var n = inEvent.activator.hasNode(); if (n) { var r = this.activatorOffset = this.getPageOffset(n); this.applyPosition({top: r.top + (this.showOnTop ? 0 : r.height), left: r.left, width: r.width}); } } this.show(); return true; }, applyPosition: function(inRect) { var s = ""; for (var n in inRect) { s += (n + ":" + inRect[n] + (isNaN(inRect[n]) ? "; " : "px; ")); } this.addStyles(s); }, getPageOffset: function(inNode) { // getBoundingClientRect returns top/left values which are relative to the viewport and not absolute var r = inNode.getBoundingClientRect(); // IE8 doesn't return window.page{X/Y}Offset & r.{height/width} // FIXME: Perhaps use an alternate universal method instead of conditionals var pageYOffset = (window.pageYOffset === undefined) ? document.documentElement.scrollTop : window.pageYOffset; var pageXOffset = (window.pageXOffset === undefined) ? document.documentElement.scrollLeft : window.pageXOffset; var rHeight = (r.height === undefined) ? (r.bottom - r.top) : r.height; var rWidth = (r.width === undefined) ? (r.right - r.left) : r.width; return {top: r.top + pageYOffset, left: r.left + pageXOffset, height: rHeight, width: rWidth}; }, //* @protected /* Adjusts the menu position to fit inside the current window size. /* Note that we aren't currently adjusting picker scroller heights. */ adjustPosition: function() { if (this.showing && this.hasNode()) { if (this.scrolling && !this.showOnTop) { this.getScroller().setMaxHeight(this.maxHeight+"px"); } this.removeClass("onyx-menu-up"); //reset the left position before we get the bounding rect for proper horizontal calculation if (!this.floating) { this.applyPosition({left: "auto"}); } var b = this.node.getBoundingClientRect(); var bHeight = (b.height === undefined) ? (b.bottom - b.top) : b.height; var innerHeight = (window.innerHeight === undefined) ? document.documentElement.clientHeight : window.innerHeight; var innerWidth = (window.innerWidth === undefined) ? document.documentElement.clientWidth : window.innerWidth; //position the menu above the activator if it's getting cut off, but only if there's more room above than below this.menuUp = (b.top + bHeight > innerHeight) && ((innerHeight - b.bottom) < (b.top - bHeight)); this.addRemoveClass("onyx-menu-up", this.menuUp); //if floating, adjust the vertical positioning if (this.floating) { var r = this.activatorOffset; //if the menu doesn't fit below the activator, move it up if (this.menuUp) { this.applyPosition({top: (r.top - bHeight + (this.showOnTop ? r.height : 0)), bottom: "auto"}); } else { //if the top of the menu is above the top of the activator and there's room to move it down, do so if ((b.top < r.top) && (r.top + (this.showOnTop ? 0 : r.height) + bHeight < innerHeight)) { this.applyPosition({top: r.top + (this.showOnTop ? 0 : r.height), bottom: "auto"}); } } } //adjust the horizontal positioning to keep the menu from being cut off on the right if ((b.right) > innerWidth) { if (this.floating){ this.applyPosition({left:innerWidth-b.width}); } else { this.applyPosition({left: -(b.right - innerWidth)}); } } //finally prevent the menu from being cut off on the left if (b.left < 0) { if (this.floating){ this.applyPosition({left: 0, right:"auto"}); } else { //handle the situation where a non-floating menu is right or left aligned if (this.getComputedStyleValue("right") == "auto"){ this.applyPosition({left:-b.left}); } else { this.applyPosition({right:b.left}); } } } //adjust the scroller height based on room available - only doing this for menus currently if (this.scrolling && !this.showOnTop){ b = this.node.getBoundingClientRect(); //update to the current menu position var scrollerHeight; if (this.menuUp){ scrollerHeight = (this.maxHeight < b.bottom) ? this.maxHeight : b.bottom; } else { scrollerHeight = ((b.top + this.maxHeight) < innerHeight) ? this.maxHeight : (innerHeight - b.top); } this.getScroller().setMaxHeight(scrollerHeight+"px"); } } }, resizeHandler: function() { this.inherited(arguments); this.adjustPosition(); }, requestHide: function(){ this.setShowing(false); } });