Skip to content

Commit

Permalink
Refactored offset logic into utility for re-use
Browse files Browse the repository at this point in the history
  • Loading branch information
MeoMix committed May 18, 2015
1 parent 34b7c3d commit a352151
Show file tree
Hide file tree
Showing 15 changed files with 221 additions and 202 deletions.
39 changes: 39 additions & 0 deletions src/js/common/utility.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,44 @@

var secondsDuration = seconds + (60 * minutes) + (60 * 60 * hours);
return secondsDuration;
},

// Determines if a given elementLength will fit inside of a containerLength.
// If it overflows out of containerLength then shift it such that it does not overflow.
shiftOffset: function(offset, elementLength, containerLength) {
var adjustedOffset = offset;
var overflow = offset + elementLength - containerLength;

// Shift the element based such that it stays within the container
if (offset < 0) {
adjustedOffset -= offset;
} else if (overflow > 0) {
adjustedOffset -= overflow;
}

return adjustedOffset;
},

// Determines if a given elementLength at a given offset will fit inside a containerLength.
// If it overflows out of containerLength then flip it over a given targetLength.
// targetLength and adjust are both optional.
flipInvertOffset: function(offset, elementLength, containerLength, targetLength, adjust) {
targetLength = targetLength || 0;
adjust = adjust || 0;

var adjustedOffset = offset;
var overflow = offset + elementLength - containerLength;
var flipInvertAmount = elementLength + targetLength + adjust;

if (offset < 0) {
// Move element from above target to below target.
adjustedOffset += flipInvertAmount;
}
else if (overflow > 0) {
// Move element from below target to above target.
adjustedOffset -= flipInvertAmount;
}

return adjustedOffset;
}
});
10 changes: 9 additions & 1 deletion src/js/foreground/view/behavior/tooltipable.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
var mutationObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var newText = mutation.target.getAttribute(mutation.attributeName);
this._showTooltip(boundingClientRect, newText);
this._updateTooltip(boundingClientRect, newText);
}.bind(this));
}.bind(this));

Expand Down Expand Up @@ -118,6 +118,14 @@
text: text
});
this.isShowingTooltip = true;
},

// Tell the current visible tooltip to update its text instead of re-showing it which would cause it to flicker.
_updateTooltip: function(boundingClientRect, text) {
Streamus.channels.tooltip.commands.trigger('update:tooltip', {
targetBoundingClientRect: boundingClientRect,
text: text
});
}
});

Expand Down
17 changes: 3 additions & 14 deletions src/js/foreground/view/contextMenu/contextMenuView.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

var ContextMenuTemplate = require('text!template/contextMenu/contextMenu.html');
var ContextMenuItemsView = require('foreground/view/contextMenu/contextMenuItemsView');
var utility = require('common/utility');

var ContextMenuView = Marionette.LayoutView.extend({
id: 'contextMenu',
Expand All @@ -20,8 +21,8 @@
},

onAttach: function() {
var offsetTop = this._ensureOffset(this.model.get('top'), this.$el.outerHeight(), this.model.get('containerHeight'));
var offsetLeft = this._ensureOffset(this.model.get('left'), this.$el.outerWidth(), this.model.get('containerWidth'));
var offsetTop = utility.flipInvertOffset(this.model.get('top'), this.$el.outerHeight(), this.model.get('containerHeight'));
var offsetLeft = utility.flipInvertOffset(this.model.get('left'), this.$el.outerWidth(), this.model.get('containerWidth'));

this.$el.offset({
top: offsetTop,
Expand All @@ -39,18 +40,6 @@
_onTransitionOutComplete: function() {
this.model.get('items').reset();
this.destroy();
},

// Prevent displaying ContextMenu outside of viewport by ensuring its offsets are valid.
_ensureOffset: function(offset, elementDimension, containerDimension) {
var ensuredOffset = offset;
var needsFlip = offset + elementDimension > containerDimension;

if (needsFlip) {
ensuredOffset -= elementDimension;
}

return ensuredOffset;
}
});

Expand Down
18 changes: 3 additions & 15 deletions src/js/foreground/view/saveSongs/saveSongsRegion.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ define(function(require) {
var SimpleMenu = require('foreground/model/element/simpleMenu');
var SimpleMenuView = require('foreground/view/element/simpleMenuView');
var CreatePlaylistDialogView = require('foreground/view/dialog/createPlaylistDialogView');
var utility = require('common/utility');

var SaveSongsRegion = Marionette.Region.extend({
signInManager: null,
Expand Down Expand Up @@ -45,8 +46,8 @@ define(function(require) {
this.show(simpleMenuView);

// TODO: Maybe it's better to position completely over the button on flip? Would need a bit more math.
var offsetTop = this._ensureOffset(options.top, simpleMenuView.$el.outerHeight(), this.$el.height());
var offsetLeft = this._ensureOffset(options.left, simpleMenuView.$el.outerWidth(), this.$el.width());
var offsetTop = utility.flipInvertOffset(options.top, simpleMenuView.$el.outerHeight(), this.$el.height());
var offsetLeft = utility.flipInvertOffset(options.left, simpleMenuView.$el.outerWidth(), this.$el.width());

simpleMenuView.$el.offset({
top: offsetTop,
Expand All @@ -65,19 +66,6 @@ define(function(require) {
Streamus.channels.dialog.commands.trigger('show:dialog', CreatePlaylistDialogView, {
songs: songs
});
},

// TODO: Keep DRY w/ contextmenu
// Prevent displaying ContextMenu outside of viewport by ensuring its offsets are valid.
_ensureOffset: function(offset, elementDimension, containerDimension) {
var ensuredOffset = offset;
var needsFlip = offset + elementDimension > containerDimension;

if (needsFlip) {
ensuredOffset -= elementDimension;
}

return ensuredOffset;
}
});

Expand Down
2 changes: 1 addition & 1 deletion src/js/foreground/view/stream/clearStreamButtonView.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},

events: {
'click': '_onClick',
'click': '_onClick'
},

modelEvents: {
Expand Down
51 changes: 13 additions & 38 deletions src/js/foreground/view/tooltip/tooltipRegion.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

var TooltipView = require('foreground/view/tooltip/tooltipView');
var Tooltip = require('foreground/model/tooltip/tooltip');
var utility = require('common/utility');

var TooltipRegion = Marionette.Region.extend({
initialize: function() {
this.listenTo(Streamus.channels.tooltip.commands, 'show:tooltip', this._showTooltip);
this.listenTo(Streamus.channels.tooltip.commands, 'hide:tooltip', this._hideTooltip);
this.listenTo(Streamus.channels.tooltip.commands, 'update:tooltip', this._updateTooltip);
},

_showTooltip: function(options) {
Expand All @@ -29,6 +31,13 @@
}
},

_updateTooltip: function(options) {
if (!_.isUndefined(this.currentView)) {
this.currentView.model.set('text', options.text);
this._setTooltipViewOffset(this.currentView, options.targetBoundingClientRect);
}
},

_setTooltipViewOffset: function(tooltipView, boundingClientRect) {
var tooltipWidth = tooltipView.el.offsetWidth;
var tooltipHeight = tooltipView.el.offsetHeight;
Expand All @@ -51,51 +60,17 @@
left: boundingClientRect.left + targetWidth / 2 - tooltipWidth / 2
};

var adjustedLeftOffset = this._shiftLeftOffset(targetOffset.left, window.innerWidth, tooltipWidth);
var adjustedTopOffset = this._flipInvertTopOffset(targetOffset.top, window.innerHeight, adjustY, targetHeight, tooltipHeight);
var adjustedLeftOffset = utility.shiftOffset(targetOffset.left, tooltipWidth, window.innerWidth);
// Double the adjust value because it has already been added once to topOffset before taking into account adjustments.
// So, need to double it when inverting to counter-act the existing amount.
var adjustedTopOffset = utility.flipInvertOffset(targetOffset.top, tooltipHeight, window.innerHeight, targetHeight, adjustY * 2);

var adjustedOffset = {
top: adjustedTopOffset,
left: adjustedLeftOffset
};

return adjustedOffset;
},

// Figure out whether the tooltip fits inside the viewport when centered over the target.
// If it is not inside the viewport then determine the amount of shifting it needs to fit.
_shiftLeftOffset: function(leftOffset, viewportLength, tooltipWidth) {
var adjustedLeftOffset = leftOffset;
var overflow = leftOffset + tooltipWidth - viewportLength;

// Shift the tooltip left/right based on how much it needs to shift to be able to fit inside the viewport.
if (leftOffset < 0) {
adjustedLeftOffset -= leftOffset;
} else if(overflow > 0) {
adjustedLeftOffset -= overflow;
}

return adjustedLeftOffset;
},

// Figure out whether the tooltip fits beneath the target. If not, get a new topOffset for it to be flipped.
_flipInvertTopOffset: function(topOffset, viewportHeight, adjust, targetHeight, tooltipHeight) {
var adjustedTopOffset = topOffset;
var overflow = topOffset + tooltipHeight - viewportHeight;
// Double the adjust value because it has already been added once to topOffset before taking into account adjustments.
// So, need to double it when inverting to counter-act the existing amount.
var flipInvertAmount = tooltipHeight + targetHeight + (adjust * 2);

if (topOffset < 0) {
// This logic will move the tooltip from above the target to beneath the target.
adjustedTopOffset += flipInvertAmount;
}
else if (overflow > 0) {
// This logic will move the tooltip from beneath the target to above the target.
adjustedTopOffset -= flipInvertAmount;
}

return adjustedTopOffset;
}
});

Expand Down
8 changes: 8 additions & 0 deletions src/js/foreground/view/tooltip/tooltipView.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
content: '[data-ui~=content]'
},

modelEvents: {
'change:text': '_onChangeText'
},

// Move the tooltip's location to a spot on the page and fade it in
showAtOffset: function(offset) {
this.$el.css(offset);
Expand All @@ -23,6 +27,10 @@
this.$el.removeClass('is-visible');
},

_onChangeText: function(model, text) {
this.ui.content.text(text);
},

_onTransitionOutComplete: function() {
this.destroy();
}
Expand Down
3 changes: 1 addition & 2 deletions src/js/test/common/commonSpecLoader.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
define(function(require) {
'use strict';

// /model/
require('test/common/model/utility.spec');
require('test/common/utility.spec');
});
49 changes: 0 additions & 49 deletions src/js/test/common/model/utility.spec.js

This file was deleted.

0 comments on commit a352151

Please sign in to comment.