forked from extern/egroupware
232 lines
6.7 KiB
TypeScript
232 lines
6.7 KiB
TypeScript
/**
|
|
* EGroupware eTemplate2 - Functions which allow resizing of table headers
|
|
*
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
* @package etemplate
|
|
* @subpackage dataview
|
|
* @link https://www.egroupware.org
|
|
* @author Andreas Stöckel
|
|
* @copyright EGroupware GmbH 2011-2021
|
|
*/
|
|
|
|
import {egw} from "../jsapi/egw_global";
|
|
|
|
/**
|
|
* This set of functions is currently only supporting resizing in ew-direction
|
|
*/
|
|
|
|
export class et2_dataview_view_resizable
|
|
{
|
|
|
|
// Define some constants
|
|
public static readonly RESIZE_BORDER = 12;
|
|
public static readonly RESIZE_MIN_WIDTH = 25;
|
|
public static readonly RESIZE_ADD = 2; // Used to ensure mouse is under the resize element after resizing has finished
|
|
|
|
|
|
public static helper : JQuery = null;
|
|
public static overlay : JQuery = null;
|
|
public static didResize = false;
|
|
public static resizeWidth = 0;
|
|
|
|
// In resize region returns whether the mouse is currently in the
|
|
// "resizeRegion"
|
|
public static inResizeRegion(_x, _elem)
|
|
{
|
|
var ol = _x - _elem.offset().left;
|
|
return (ol > (_elem.outerWidth(true) - et2_dataview_view_resizable.RESIZE_BORDER));
|
|
}
|
|
|
|
public static startResize(_outerElem, _elem, _callback, _column)
|
|
{
|
|
if (this.overlay == null || this.helper == null)
|
|
{
|
|
// Prevent text selection
|
|
// FireFox handles highlight prevention (text selection) different than other browsers
|
|
if (typeof _elem[0].style.MozUserSelect !="undefined")
|
|
{
|
|
_elem[0].style.MozUserSelect = "none";
|
|
}
|
|
else
|
|
{
|
|
_elem[0].onselectstart = function() {
|
|
return false;
|
|
};
|
|
}
|
|
|
|
// Indicate resizing is in progress
|
|
jQuery(_outerElem).addClass('egwResizing');
|
|
|
|
// Reset the "didResize" flag
|
|
this.didResize = false;
|
|
|
|
// Create the resize helper
|
|
var left = _elem.offset().left;
|
|
this.helper = jQuery(document.createElement("div"))
|
|
.addClass("egwResizeHelper")
|
|
.appendTo("body")
|
|
.css("top", _elem.offset().top + "px")
|
|
.css("left", left + "px")
|
|
.css("height", _outerElem.outerHeight(true) + "px");
|
|
|
|
// Create the overlay which will be catching the mouse movements
|
|
this.overlay = jQuery(document.createElement("div"))
|
|
.addClass("egwResizeOverlay")
|
|
|
|
.bind("mousemove", function(e) {
|
|
this.didResize = true;
|
|
this.resizeWidth = Math.max(e.pageX - left + et2_dataview_view_resizable.RESIZE_ADD,
|
|
_column && _column.minWidth ? _column.minWidth : et2_dataview_view_resizable.RESIZE_MIN_WIDTH
|
|
);
|
|
this.helper.css("width", this.resizeWidth + "px");
|
|
}.bind(this))
|
|
|
|
.bind("mouseup", function() {
|
|
this.stopResize(_outerElem);
|
|
|
|
// Reset text selection
|
|
_elem[0].onselectstart = null;
|
|
|
|
// Call the callback if the user actually performed a resize
|
|
if (this.didResize)
|
|
{
|
|
_callback(this.resizeWidth);
|
|
}
|
|
}.bind(this))
|
|
.appendTo("body");
|
|
}
|
|
}
|
|
|
|
public static stopResize(_outerElem)
|
|
{
|
|
|
|
jQuery(_outerElem).removeClass('egwResizing');
|
|
if (this.helper != null)
|
|
{
|
|
this.helper.remove();
|
|
this.helper = null;
|
|
}
|
|
|
|
if (this.overlay != null)
|
|
{
|
|
this.overlay.remove();
|
|
this.overlay = null;
|
|
}
|
|
}
|
|
|
|
public static makeResizeable = function(_elem, _callback, _context)
|
|
{
|
|
// Get the table surrounding the given element - this element is used to
|
|
// align the helper properly
|
|
var outerTable = _elem.closest("table");
|
|
|
|
// Bind the "mousemove" event in the "resize" namespace
|
|
_elem.bind("mousemove.resize", function(e) {
|
|
var stopResize = false;
|
|
// Stop switch to resize cursor if the mouse position
|
|
// is more intended for scrollbar not the resize edge
|
|
// 8pixel is an arbitary number for scrolbar area
|
|
if (e.target.clientHeight < e.target.scrollHeight && e.target.offsetWidth - e.offsetX <= 8)
|
|
{
|
|
stopResize = true;
|
|
}
|
|
_elem.css("cursor", et2_dataview_view_resizable.inResizeRegion(e.pageX, _elem) && !stopResize? "ew-resize" : "auto");
|
|
});
|
|
|
|
// Bind the "mousedown" event in the "resize" namespace
|
|
_elem.bind("mousedown.resize", function(e) {
|
|
var stopResize = false;
|
|
// Stop resize if the mouse position is more intended
|
|
// for scrollbar not the resize edge
|
|
// 8pixel is an arbitary number for scrolbar area
|
|
if (e.target.clientHeight < e.target.scrollHeight && e.target.offsetWidth - e.offsetX <= 8)
|
|
{
|
|
stopResize = true;
|
|
}
|
|
// Do not triger startResize if clicked element is select-tag, as it may causes conflict in some browsers
|
|
if (et2_dataview_view_resizable.inResizeRegion(e.pageX, _elem) && e.target.tagName != 'SELECT' && !stopResize)
|
|
{
|
|
// Start the resizing
|
|
et2_dataview_view_resizable.startResize(outerTable, _elem, function(_w) {
|
|
_callback.call(_context, _w);
|
|
}, _context);
|
|
}
|
|
|
|
});
|
|
|
|
// Bind double click for auto-size
|
|
_elem.dblclick(function(e) {
|
|
// Just show message for relative width columns
|
|
if(_context && _context.relativeWidth)
|
|
{
|
|
return egw.message(egw.lang('You tried to automatically size a flex column, which always takes the rest of the space','info'));
|
|
}
|
|
// Find column class - it's usually the first one
|
|
var col_class = '';
|
|
for(var i = 0; i < this.classList.length; i++)
|
|
{
|
|
if(this.classList[i].indexOf('gridCont') === 0)
|
|
{
|
|
col_class = this.classList[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Find widest part, including header
|
|
var column = jQuery(this);
|
|
column.children().css('width','auto');
|
|
var max_width = column.children().children().innerWidth();
|
|
var padding = column.outerWidth(true) - max_width;
|
|
|
|
var resize = jQuery(this).closest('.egwGridView_outer')
|
|
.find('tbody td.'+col_class+'> div:first-child')
|
|
.add(column.children())
|
|
// Set column width to auto to allow space for everything to flow
|
|
.css('width','auto');
|
|
resize.children()
|
|
.css({'white-space':'nowrap'})
|
|
.each(function()
|
|
{
|
|
var col = jQuery(this);
|
|
// Find visible (text) children and force them to not wrap
|
|
var children = col.find('span:visible, time:visible, label:visible')
|
|
.css({'white-space':'nowrap'});
|
|
this.offsetWidth;
|
|
children.each(function()
|
|
{
|
|
var child = jQuery(this);
|
|
this.offsetWidth;
|
|
if(child.outerWidth() > max_width)
|
|
{
|
|
max_width = child.outerWidth();
|
|
}
|
|
window.getComputedStyle(this).width;
|
|
});
|
|
this.offsetWidth;
|
|
if(col.innerWidth() > max_width)
|
|
{
|
|
max_width = col.innerWidth();
|
|
}
|
|
|
|
// Reset children
|
|
children.css('white-space','');
|
|
children.css('display','');
|
|
}
|
|
)
|
|
.css({'white-space':''});
|
|
|
|
// Reset column
|
|
column.children().css('width','');
|
|
resize.css('width','');
|
|
_callback.call(_context, max_width+padding);
|
|
});
|
|
};
|
|
|
|
public static et2_dataview_resetResizeable = function(_elem)
|
|
{
|
|
// Remove all events in the ".resize" namespace from the element
|
|
_elem.unbind(".resize");
|
|
}
|
|
}
|
|
|