Skip to content

Commit

Permalink
fix: align next sub-menu on the left again if needed
Browse files Browse the repository at this point in the history
  • Loading branch information
web-padawan committed Mar 26, 2019
1 parent b47e4d5 commit 131ee47
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 22 deletions.
3 changes: 2 additions & 1 deletion src/vaadin-context-menu-overlay.html
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@
xMax: overlayRect.right - contentRect.width,
yMax,
left: overlayRect.left,
top: overlayRect.top
top: overlayRect.top,
width: contentRect.width
};
}
}
Expand Down
47 changes: 35 additions & 12 deletions src/vaadin-context-menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -556,28 +556,51 @@
['right-aligned', 'bottom-aligned'].forEach(attr => overlay.removeAttribute(attr));

// Maximum x and y values are imposed by content size and overlay limits.
const {xMax, yMax, left, top} = overlay.getBoundaries();
const {xMax, yMax, left, top, width} = overlay.getBoundaries();
// Reuse saved x and y event values, in order to this method be used async
// in the `vaadin-overlay-change` which guarantees that overlay is ready
const x = this.__x || left;
let x = this.__x || left;
const y = this.__y || top;

// Select one overlay corner and move to the event x/y position.
// Then set styling attrs for flex-aligning the content appropriatelly.
// Then set styling attrs for flex-aligning the content appropriately.
const wdthVport = document.documentElement.clientWidth;
const hghtVport = document.documentElement.clientHeight;

// Align to the parent menu overlay, if any.
const parent = overlay.parentOverlay;
if (parent && parent.hasAttribute('right-aligned')) {
const parentStyle = getComputedStyle(parent);
let alignedToParent = false;
if (parent) {
const parentContentRect = parent.$.overlay.getBoundingClientRect();
overlay.setAttribute('right-aligned', '');
style.right = parseFloat(parentStyle.right) + parentContentRect.width + 'px';
} else if (x < wdthVport / 2 || x < xMax) {
style.left = x + 'px';
} else {
style.right = Math.max(0, (wdthVport - x)) + 'px';
overlay.setAttribute('right-aligned', '');
if (parent.hasAttribute('right-aligned')) {
const parentStyle = getComputedStyle(parent);

const getPadding = (el, direction) => {
return parseFloat(getComputedStyle(el.$.content)['padding' + direction]);
};
const right = parseFloat(parentStyle.right) + parentContentRect.width;
const padding = getPadding(parent, 'Left') + getPadding(overlay, 'Right');

// Preserve right-aligned, if possible.
if ((wdthVport - (right - padding)) > width) {
overlay.setAttribute('right-aligned', '');
style.right = right - padding + 'px';
alignedToParent = true;
} else if (!(x < wdthVport / 2 || x < xMax)) {
// We use parent menu item to predict "x", which isn't accurate.
// Adjust it now, based on the rendered sub-menu content width.
x = x - (width - parentContentRect.width);
}
}
}

if (!alignedToParent) {
if (x < wdthVport / 2 || x < xMax) {
style.left = x + 'px';
} else {
style.right = Math.max(0, (wdthVport - x)) + 'px';
overlay.setAttribute('right-aligned', '');
}
}
if (y < hghtVport / 2 || y < yMax) {
style.top = y + 'px';
Expand Down
71 changes: 62 additions & 9 deletions test/items.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@
{text: 'foo-0', children:
[
{text: 'foo-0-0', checked: true},
{text: 'foo-0-1', disabled: true}
{text: 'foo-0-1', disabled: true},
{text: 'foo-0-2', children: [
{text: 'foo-0-2-0'}
]},
]
},
{text: 'foo-1'}
Expand Down Expand Up @@ -130,19 +133,69 @@
});

it('should open the subMenu on the left if root menu is right-aligned', done => {
let padding;
subMenu.close();
const rootItemRect = menuComponents()[0].getBoundingClientRect();
rootMenu.$.overlay.style.removeProperty('left');
rootMenu.$.overlay.style.right = rootItemRect.width + 'px';
rootMenu.$.overlay.setAttribute('right-aligned', '');
open(menuComponents()[0]);
const rootItem = menuComponents()[0];
const rootItemRect = rootItem.getBoundingClientRect();
const rootOverlay = rootMenu.$.overlay;
rootOverlay.style.removeProperty('left');
rootOverlay.style.right = rootItemRect.width + 'px';
rootOverlay.setAttribute('right-aligned', '');
padding = parseFloat(getComputedStyle(rootOverlay.$.content).paddingLeft) * 2;
open(rootItem);

Polymer.RenderStatus.afterNextRender(subMenu, () => {
expect(subMenu.$.overlay.hasAttribute('right-aligned')).to.be.true;
const rootMenuRect = rootMenu.$.overlay.$.content.getBoundingClientRect();
const rootMenuRect = rootOverlay.$.content.getBoundingClientRect();
const subMenuRect = subMenu.$.overlay.$.content.getBoundingClientRect();
expect(subMenuRect.right).to.be.closeTo(rootMenuRect.left, 1);
done();
expect(subMenuRect.right).to.be.closeTo(rootMenuRect.left + padding, 1);

const nestedItem = menuComponents(subMenu)[2];
padding = parseFloat(getComputedStyle(subMenu.$.overlay.$.content).paddingLeft) * 2;
open(nestedItem);

Polymer.RenderStatus.afterNextRender(subMenu, () => {
const subMenu2 = getSubMenu(subMenu);
expect(subMenu2.$.overlay.hasAttribute('right-aligned')).to.be.true;
const subMenu2Rect = subMenu2.$.overlay.$.content.getBoundingClientRect();
expect(subMenu2Rect.right).to.be.closeTo(subMenuRect.left + padding, 1);
done();
});
});
});

it('should open the second subMenu on the right again if not enough space', done => {
let padding;
subMenu.close();
rootMenu.items[0].children[2].text = 'foo-0-2-longer';

const rootItem = menuComponents()[0];
const rootItemRect = rootItem.getBoundingClientRect();
const rootOverlay = rootMenu.$.overlay;
rootOverlay.style.removeProperty('left');
rootOverlay.style.right = rootItemRect.width + 'px';
rootOverlay.setAttribute('right-aligned', '');
padding = parseFloat(getComputedStyle(rootOverlay.$.content).paddingLeft) * 2;
open(rootItem);

Polymer.RenderStatus.afterNextRender(subMenu, () => {
expect(subMenu.$.overlay.hasAttribute('right-aligned')).to.be.true;
const rootMenuRect = rootOverlay.$.content.getBoundingClientRect();
const subMenuRect = subMenu.$.overlay.$.content.getBoundingClientRect();
expect(subMenuRect.right).to.be.closeTo(rootMenuRect.left + padding, 1);

const nestedItem = menuComponents(subMenu)[2];
const nestedItemRect = nestedItem.getBoundingClientRect();
padding = parseFloat(getComputedStyle(subMenu.$.overlay.$.content).paddingLeft) * 2;
open(nestedItem);

Polymer.RenderStatus.afterNextRender(subMenu, () => {
const subMenu2 = getSubMenu(subMenu);
expect(subMenu2.$.overlay.hasAttribute('right-aligned')).to.be.false;
const subMenu2Rect = subMenu2.$.overlay.$.content.getBoundingClientRect();
expect(subMenu2Rect.left).to.be.closeTo(nestedItemRect.right, 1);
done();
});
});
});
}
Expand Down

0 comments on commit 131ee47

Please sign in to comment.