MediaWiki:Grabbox.js
Jump to navigation
Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes.
- Internet Explorer: hold down the Ctrl key and click the Refresh or Reload button, or press Ctrl+F5.
- Firefox: hold down the Shift key while clicking Reload; alternatively press Ctrl+F5 or Ctrl-Shift-R.
- Opera, Konqueror and Safari users can just click the Reload button.
- Chrome: press Ctrl+F5 or Shift+F5
$(document).ready(function() {
var isDragging = false;
var offsetX, offsetY;
var $currentBox;
var originalPosition;
var $placeholder;
$(".grabbox-header").on("mousedown", function(e) {
isDragging = true;
$currentBox = $(this).closest(".grabbox");
// Safety check
if (!$currentBox.length) return;
// Store original position type
originalPosition = $currentBox.css("position");
var currentOffset;
// Create placeholder with same dimensions (only if it doesn't exist yet)
if (originalPosition !== "fixed" && !$currentBox.data('placeholder')) {
// Get offset BEFORE inserting placeholder
currentOffset = $currentBox.offset();
var boxWidth = $currentBox.outerWidth();
var boxHeight = $currentBox.outerHeight();
$placeholder = $('<div class="grabbox-placeholder"></div>').css({
width: boxWidth + "px",
height: boxHeight + "px",
visibility: "hidden",
display: $currentBox.css("display")
});
// Insert placeholder before moving box
$currentBox.before($placeholder);
// Store reference so we don't create multiple placeholders
$currentBox.data('placeholder', $placeholder);
// Now set fixed position using viewport-relative coordinates
if (currentOffset) {
$currentBox.css({
position: "fixed",
left: (currentOffset.left - $(window).scrollLeft()) + "px",
top: (currentOffset.top - $(window).scrollTop()) + "px",
margin: 0,
zIndex: 99999
});
}
}
// Remove any transform
if ($currentBox.css("transform") !== "none") {
currentOffset = currentOffset || $currentBox.offset();
if (currentOffset) {
$currentBox.css({
transform: "none",
left: (currentOffset.left - $(window).scrollLeft()) + "px",
top: (currentOffset.top - $(window).scrollTop()) + "px"
});
}
}
// Calculate offset from click point using viewport-relative coordinates
offsetX = e.clientX - parseFloat($currentBox.css('left'));
offsetY = e.clientY - parseFloat($currentBox.css('top'));
$(this).css("cursor", "grabbing");
$('body').css('user-select', 'none');
e.preventDefault();
e.stopPropagation();
});
$(document).on("mousemove", function(e) {
if (isDragging && $currentBox) {
var boxWidth = $currentBox.outerWidth();
var boxHeight = $currentBox.outerHeight();
// Calculate desired position using viewport-relative coordinates
var newLeft = e.clientX - offsetX;
var newTop = e.clientY - offsetY;
// Only apply clamping if #mw-page-base is visible (normal page layout)
var $pageBase = $('#mw-page-base');
if (!$pageBase.length || $pageBase.css('display') !== 'none') {
// Get content area bounds
var $content = $('#mw-content-text, .mw-parser-output').first();
if (!$content.length) $content = $('#content');
var contentBounds = $content.offset();
var contentWidth = $content.outerWidth();
var contentHeight = $content.outerHeight();
// Convert content bounds to viewport coordinates for clamping
var viewportContentLeft = contentBounds.left - $(window).scrollLeft();
var viewportContentTop = contentBounds.top - $(window).scrollTop();
// Clamp to content bounds (in viewport coordinates)
newLeft = Math.max(viewportContentLeft,
Math.min(newLeft, viewportContentLeft + contentWidth - boxWidth));
newTop = Math.max(viewportContentTop,
Math.min(newTop, viewportContentTop + contentHeight - boxHeight));
}
$currentBox.css({
left: newLeft + "px",
top: newTop + "px"
});
}
});
$(document).on("mouseup", function() {
if (isDragging) {
isDragging = false;
$(".grabbox-header").css("cursor", "grab");
$('body').css('user-select', '');
// Placeholder stays - don't remove it
$currentBox = null;
}
});
// Add grab cursor to headers by default
$(".grabbox-header").css("cursor", "grab");
});