diff --git a/src/DebugBar/Resources/debugbar.css b/src/DebugBar/Resources/debugbar.css index 1209dba..e845bb1 100644 --- a/src/DebugBar/Resources/debugbar.css +++ b/src/DebugBar/Resources/debugbar.css @@ -106,6 +106,13 @@ a.phpdebugbar-restore-btn { border-right: 1px solid #ddd; } +.phpdebugbar-dragging a.phpdebugbar-restore-btn { + cursor: move; + cursor: grabbing; + cursor: -moz-grabbing; + cursor: -webkit-grabbing; +} + div.phpdebugbar-resize-handle { display: none; height: 4px; diff --git a/src/DebugBar/Resources/debugbar.js b/src/DebugBar/Resources/debugbar.js index fa19596..0cadb5a 100644 --- a/src/DebugBar/Resources/debugbar.js +++ b/src/DebugBar/Resources/debugbar.js @@ -435,6 +435,8 @@ if (typeof(PhpDebugBar) == 'undefined') { this.activePanelName = null; this.activeDatasetId = null; this.hideEmptyTabs = false; + this.restorePosition = localStorage.getItem('phpdebugbar-restore-position'); + this.restoreOffset = localStorage.getItem('phpdebugbar-restore-offset') || 0; this.datesetTitleFormater = new DatasetTitleFormater(this); this.options.bodyMarginBottomHeight = parseInt($('body').css('margin-bottom')); try { @@ -484,6 +486,9 @@ if (typeof(PhpDebugBar) == 'undefined') { // Reset height to ensure bar is still visible this.setHeight(this.$body.height()); + if (this.restorePosition) { + this.resizeRestoreButton(); + } }, /** @@ -551,6 +556,12 @@ if (typeof(PhpDebugBar) == 'undefined') { self.restore(); }); + // dragging of restore button + this.$restorebtn.on('mousedown touchstart', function (e) { + self.draggingRestoreButtonEvent(e); + e.preventDefault(); + }); + // open button this.$openbtn = $('').addClass(csscls('open-btn')).appendTo(this.$headerRight).hide(); this.$openbtn.click(function() { @@ -844,6 +855,9 @@ if (typeof(PhpDebugBar) == 'undefined') { this.$restorebtn.show(); localStorage.setItem('phpdebugbar-open', '0'); this.$el.addClass(csscls('closed')); + if (this.restorePosition) { + this.resizeRestoreButton(); + } this.recomputeBottomOffset(); }, @@ -862,6 +876,10 @@ if (typeof(PhpDebugBar) == 'undefined') { * @this {DebugBar} */ restore: function() { + if (this.$el.hasClass(csscls('dragging'))){ + this.$el.removeClass(csscls('dragging')); + return; + } this.$resizehdle.show(); this.$header.show(); this.$restorebtn.hide(); @@ -873,6 +891,7 @@ if (typeof(PhpDebugBar) == 'undefined') { this.showTab(); } this.$el.removeClass(csscls('closed')); + this.$el.css('left', ''); this.resize(); }, @@ -891,6 +910,155 @@ if (typeof(PhpDebugBar) == 'undefined') { } }, + /** + * allows you to move the revert button so that other components of the page can be displayed + */ + draggingRestoreButtonEvent: function(e) { + var self = this; + if (!self.isClosed()) return; + + // Track initial mouse position and element position + var initialMouseX = e.type === 'mousedown' ? e.clientX : e.touches[0].clientX; + var initialPosX = self.$el.position().left; + var moved = false; + var target = e.target; + + + function doDrag(e) { + // Calculate the change in mouse position + var clientX = e.type === 'mousemove' ? e.clientX : e.touches[0].clientX; + var deltaX = clientX - initialMouseX; + + // When not changed, don't + if (deltaX !== 0) { + moved = true; + } + + // Update the position of the element + var newPosX = initialPosX + deltaX; + + // Ensure the new position is within screen boundaries + newPosX = self.recomputeRestorePositionX(newPosX); + + self.$el.css('left', newPosX + 'px'); + self.$el.css('right', 'auto'); + self.$el.addClass(csscls('dragging')); + } + + function stopDragging() { + // Unbind the move and up/end events + $(document).off('mousemove.drag touchmove.drag', doDrag); + $(document).off('mouseup.drag touchend.drag', stopDragging); + + // Check if this was actually a drag instead of a click + if (!moved) { + $(target).trigger('click'); + return; + } + + // Save the new position as a percentage of screen width + var finalPosX = self.$el.position().left; + var screenWidth = $(window).width(); + + var positionPercentage = (finalPosX / screenWidth) * 100; // Store as percentage + + if (positionPercentage < 10) { + self.restorePosition = 'bottomLeft'; + self.restoreOffset = finalPosX; + } else if (positionPercentage > 90) { + self.restorePosition = 'bottomRight'; + self.restoreOffset = screenWidth - finalPosX; + } else { + self.restorePosition = 'bottomPercentage'; + self.restoreOffset = positionPercentage; + } + + localStorage.setItem('phpdebugbar-restore-position', self.restorePosition); + localStorage.setItem('phpdebugbar-restore-offset', self.restoreOffset); + + setTimeout(function () { + self.resizeRestoreButton(); + self.$el.removeClass(csscls('dragging')); + }, 500); + } + + // Bind the move and up/end events + $(document).on('mousemove.drag touchmove.drag', doDrag); + $(document).on('mouseup.drag touchend.drag', stopDragging); + }, + + /** + * Recomputes the left css property of the restore btn for dragging + * restore button always has to be visible and not be left off the screen + */ + recomputeRestorePositionX: function (posX) { + if (!this.isClosed()) return; + + var screenWidth = $(window).width(); + var elementWidth = this.$restorebtn.outerWidth(); + + // adjust position to ensure it doesn't go out of bounds + if (posX < 0) { + posX = 0; + } else if (posX + elementWidth > screenWidth) { + posX = screenWidth - elementWidth; // ensure it doesn't overflow + } + + return posX; + }, + + /** + * Adjust the restore button's position when the window is resized + */ + resizeRestoreButton: function() { + if (!this.isClosed()) return; + + var self = this; + + // Get the saved position and offset/percentage + var position = this.restorePosition; + var positionOffset = parseFloat(this.restoreOffset); + + if (isNaN(positionOffset) || !position){ + return; + } + + // Recalculate the position based on the new screen width + var screenWidth = $(window).width(); + + var elementWidth = this.$restorebtn.outerWidth(); + + var newPosX = positionOffset; + if (position === 'bottomPercentage') { + // Calculate the new position in pixels + newPosX = (positionOffset / 100) * screenWidth; + + } else if (position === 'bottomRight') { + newPosX = newPosX - elementWidth + } + + // Ensure the new position is within screen boundaries + newPosX = Math.max(0, Math.min(newPosX, screenWidth - elementWidth)); + + if (position === 'bottomRight') { + // Set the offset + self.$el.css('left', 'auto'); + self.$el.css('right', newPosX + 'px'); + + // Apply the calculated borders to the restore button + this.$restorebtn.css('border-left', '1px solid #ddd'); + this.$restorebtn.css('border-right', newPosX > 0 ? '1px solid #ddd' : '1px solid transparent'); + } else { + // Set the offset + self.$el.css('left', newPosX + 'px'); + self.$el.css('right', 'auto'); + + // Restore the borders + this.$restorebtn.css('border-right', '1px solid #ddd'); + this.$restorebtn.css('border-left', newPosX > 0 ? '1px solid #ddd' : '1px solid transparent'); + } + }, + /** * Sets the data map used by dataChangeHandler to populate * indicators and widgets