Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/html/lib/onyx/source/Menu.js
diff options
context:
space:
mode:
Diffstat (limited to 'html/lib/onyx/source/Menu.js')
-rw-r--r--html/lib/onyx/source/Menu.js130
1 files changed, 130 insertions, 0 deletions
diff --git a/html/lib/onyx/source/Menu.js b/html/lib/onyx/source/Menu.js
new file mode 100644
index 0000000..53353a0
--- /dev/null
+++ b/html/lib/onyx/source/Menu.js
@@ -0,0 +1,130 @@
+/**
+ _onyx.Menu_ is a subkind of <a href="#onyx.Popup">onyx.Popup</a> that
+ displays a list of <a href="#onyx.MenuItems">onyx.MenuItems</a> and looks
+ like a popup menu. It is meant to be used in conjunction with an
+ <a href="#onyx.MenuDecorator">onyx.MenuDecorator</a>. 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: "3"},
+ ]}
+ ]}
+
+ A menu may be floated by setting the _floating_ property to true. When a
+ menu is not floating (the default), it will scroll with the activating
+ control, but may be obscured by surrounding content with a higher z-index.
+ When floating, it will never be obscured, but it will not scroll with the
+ activating button.
+ */
+enyo.kind({
+ name: "onyx.Menu",
+ kind: "onyx.Popup",
+ modal: true,
+ defaultKind: "onyx.MenuItem",
+ classes: "onyx-menu",
+ showOnTop: false,
+ handlers: {
+ onActivate: "itemActivated",
+ onRequestShowMenu: "requestMenuShow",
+ onRequestHideMenu: "requestHide"
+ },
+ itemActivated: function(inSender, inEvent) {
+ inEvent.originator.setActive(false);
+ return true;
+ },
+ showingChanged: function() {
+ this.inherited(arguments);
+ 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 (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.
+ belowActivator determines whether to position the top of the menu below or on top of the activator
+ */
+ adjustPosition: function(belowActivator) {
+ if (this.showing && this.hasNode()) {
+ this.removeClass("onyx-menu-up");
+
+ //reset the left position before we get the bounding rect for proper horizontal calculation
+ this.floating ? enyo.noop : 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
+ 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 + (belowActivator ? r.height : 0) + 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: r.left-(b.left + b.width - innerWidth)});
+ } else {
+ this.applyPosition({left: -(b.right - innerWidth)});
+ }
+ }
+ }
+ },
+ resizeHandler: function() {
+ this.inherited(arguments);
+ this.adjustPosition(true);
+ },
+ requestHide: function(){
+ this.setShowing(false);
+ }
+}); \ No newline at end of file