devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,045 lines (1,043 loc) • 48.2 kB
JavaScript
/**
* DevExtreme (ui/grid_core/ui.grid_core.columns_resizing_reordering.js)
* Version: 18.1.3
* Build date: Tue May 15 2018
*
* Copyright (c) 2012 - 2018 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
var $ = require("../../core/renderer"),
domAdapter = require("../../core/dom_adapter"),
eventsEngine = require("../../events/core/events_engine"),
Callbacks = require("../../core/utils/callbacks"),
typeUtils = require("../../core/utils/type"),
each = require("../../core/utils/iterator").each,
extend = require("../../core/utils/extend").extend,
eventUtils = require("../../events/utils"),
pointerEvents = require("../../events/pointer"),
dragEvents = require("../../events/drag"),
addNamespace = eventUtils.addNamespace,
modules = require("./ui.grid_core.modules"),
gridCoreUtils = require("./ui.grid_core.utils"),
fx = require("../../animation/fx");
var COLUMNS_SEPARATOR_CLASS = "columns-separator",
COLUMNS_SEPARATOR_TRANSPARENT = "columns-separator-transparent",
DRAGGING_HEADER_CLASS = "drag-header",
CELL_CONTENT_CLASS = "text-content",
HEADERS_DRAG_ACTION_CLASS = "drag-action",
TRACKER_CLASS = "tracker",
HEADERS_DROP_HIGHLIGHT_CLASS = "drop-highlight",
BLOCK_SEPARATOR_CLASS = "dx-block-separator",
HEADER_ROW_CLASS = "dx-header-row",
WIDGET_CLASS = "dx-widget",
MODULE_NAMESPACE = "dxDataGridResizingReordering",
COLUMNS_SEPARATOR_TOUCH_TRACKER_WIDTH = 10,
DRAGGING_DELTA = 5,
COLUMN_OPACITY = .5;
var allowResizing = function(that) {
return that.option("allowColumnResizing") || that.getController("columns").isColumnOptionUsed("allowResizing")
};
var allowReordering = function(that) {
return that.option("allowColumnReordering") || that.getController("columns").isColumnOptionUsed("allowReordering")
};
var TrackerView = modules.View.inherit({
_renderCore: function() {
this.callBase();
this.element().addClass(this.addWidgetPrefix(TRACKER_CLASS));
this.hide()
},
_unsubscribeFromCallback: function() {
if (this._positionChanged) {
this._tablePositionController.positionChanged.remove(this._positionChanged)
}
},
_subscribeToCallback: function() {
var that = this;
that._positionChanged = function(position) {
var $element = that.element();
if ($element && $element.hasClass(that.addWidgetPrefix(TRACKER_CLASS))) {
$element.css({
top: position.top
});
$element.height(position.height)
}
};
this._tablePositionController.positionChanged.add(that._positionChanged)
},
optionChanged: function(args) {
if ("allowColumnResizing" === args.name) {
this._unsubscribeFromCallback();
if (args.value) {
this._subscribeToCallback();
this._invalidate()
}
}
this.callBase(args)
},
init: function() {
this.callBase();
this._tablePositionController = this.getController("tablePosition");
this._subscribeToCallback()
},
isVisible: function() {
return allowResizing(this)
},
show: function() {
this.element().show()
},
hide: function() {
this.element() && this.element().hide()
},
setHeight: function(value) {
this.element().height(value)
},
dispose: function() {
this._unsubscribeFromCallback();
this.callBase()
}
});
var SeparatorView = modules.View.inherit({
_renderSeparator: function() {},
_renderCore: function(options) {
this.callBase(options);
this._isShown = true;
this._renderSeparator();
this.hide()
},
show: function() {
this._isShown = true
},
hide: function() {
this._isShown = false
},
height: function(value) {
var $element = this.element();
if ($element) {
if (typeUtils.isDefined(value)) {
$element.height(value)
} else {
return $element.height()
}
}
},
width: function(value) {
var $element = this.element();
if ($element) {
if (typeUtils.isDefined(value)) {
$element.width(value)
} else {
return $element.width()
}
}
}
});
var ColumnsSeparatorView = SeparatorView.inherit({
_renderSeparator: function() {
this.callBase();
var $element = this.element();
$element.addClass(this.addWidgetPrefix(COLUMNS_SEPARATOR_CLASS))
},
_subscribeToCallback: function() {
var $element, that = this;
that._positionChanged = function(position) {
$element = that.element();
if ($element) {
$element.css({
top: position.top
});
$element.height(position.height)
}
};
that._tablePositionController.positionChanged.add(that._positionChanged)
},
_unsubscribeFromCallback: function() {
this._positionChanged && this._tablePositionController.positionChanged.remove(this._positionChanged)
},
_init: function() {
this._isTransparent = allowResizing(this);
if (this.isVisible()) {
this._subscribeToCallback()
}
},
isVisible: function() {
return this.option("showColumnHeaders") && (allowReordering(this) || allowResizing(this))
},
optionChanged: function(args) {
if ("allowColumnResizing" === args.name) {
if (args.value) {
this._init();
this._invalidate();
this.hide(true)
} else {
this._unsubscribeFromCallback();
this._isTransparent = allowResizing(this);
this.hide(true)
}
}
this.callBase(args)
},
init: function() {
this.callBase();
this._tablePositionController = this.getController("tablePosition");
this._init()
},
show: function() {
var that = this,
$element = this.element();
if ($element && !that._isShown) {
if (that._isTransparent) {
$element.removeClass(that.addWidgetPrefix(COLUMNS_SEPARATOR_TRANSPARENT))
} else {
$element.show()
}
}
this.callBase()
},
hide: function(force) {
var $element = this.element(),
columnsSeparatorTransparent = this.addWidgetPrefix(COLUMNS_SEPARATOR_TRANSPARENT);
if ($element && (this._isShown || force)) {
if (this._isTransparent) {
$element.addClass(columnsSeparatorTransparent);
$element.show()
} else {
if ($element.hasClass(columnsSeparatorTransparent)) {
$element.removeClass(columnsSeparatorTransparent)
}
$element.hide()
}
}
this.callBase()
},
moveByX: function(outerX) {
var $element = this.element();
if ($element) {
$element.css("left", outerX - this._parentElement().offset().left)
}
},
changeCursor: function(cursorName) {
cursorName = typeUtils.isDefined(cursorName) ? cursorName : "";
var $element = this.element();
if ($element) {
$element.css("cursor", cursorName)
}
},
dispose: function() {
this._unsubscribeFromCallback();
this.callBase()
}
});
var BlockSeparatorView = SeparatorView.inherit({
init: function() {
var that = this;
this.callBase();
this.getController("data").loadingChanged.add(function(isLoading) {
if (!isLoading) {
that.hide()
}
})
},
_renderSeparator: function() {
this.callBase();
this.element().addClass(BLOCK_SEPARATOR_CLASS).html(" ")
},
hide: function() {
var that = this,
$parent = this._parentElement(),
$element = this.element();
if ($element && this._isShown) {
$element.css("display", "none")
}
if ($parent && !$parent.children("." + BLOCK_SEPARATOR_CLASS).length) {
$parent.prepend(that.element())
}
that.callBase()
},
isVisible: function() {
var groupPanelOptions = this.option("groupPanel"),
columnChooserOptions = this.option("columnChooser");
return groupPanelOptions && groupPanelOptions.visible || columnChooserOptions && columnChooserOptions.enabled
},
show: function(targetLocation) {
var that = this,
$element = this.element(),
startAnimate = function(toOptions) {
fx.stop($element, true);
fx.animate($element, {
type: "slide",
from: {
width: 0,
display: toOptions.display
},
to: toOptions,
duration: 300,
easing: "swing"
})
};
if ($element && !that._isShown) {
switch (targetLocation) {
case "group":
startAnimate({
width: "50px",
display: "inline-block"
});
break;
case "columnChooser":
startAnimate({
width: "100%",
display: "block"
});
break;
default:
$element.css("display", "")
}
}
that.callBase()
}
});
var DraggingHeaderView = modules.View.inherit({
_isDragging: false,
_getDraggingPanelByPos: function(pos) {
var result, that = this;
each(that._dragOptions.draggingPanels, function(index, draggingPanel) {
if (draggingPanel) {
var boundingRect = draggingPanel.getBoundingRect();
if (boundingRect && (void 0 === boundingRect.bottom || pos.y < boundingRect.bottom) && (void 0 === boundingRect.top || pos.y > boundingRect.top) && (void 0 === boundingRect.left || pos.x > boundingRect.left) && (void 0 === boundingRect.right || pos.x < boundingRect.right)) {
result = draggingPanel;
return false
}
}
});
return result
},
_renderCore: function() {
this.element().addClass(this.addWidgetPrefix(DRAGGING_HEADER_CLASS) + " " + this.addWidgetPrefix(CELL_CONTENT_CLASS) + " " + WIDGET_CLASS).hide()
},
_resetTargetColumnOptions: function() {
var params = this._dropOptions;
params.targetColumnIndex = -1;
delete params.targetColumnElement;
delete params.isLast;
delete params.posX;
delete params.posY
},
_getVisibleIndexObject: function(rowIndex, visibleIndex) {
if (typeUtils.isDefined(rowIndex)) {
return {
columnIndex: visibleIndex,
rowIndex: rowIndex
}
}
return visibleIndex
},
dispose: function() {
var element = this.element();
this._dragOptions = null;
element && element.parent().find("." + this.addWidgetPrefix(DRAGGING_HEADER_CLASS)).remove()
},
isVisible: function() {
var columnsController = this.getController("columns"),
commonColumnSettings = columnsController.getCommonSettings();
return this.option("showColumnHeaders") && (allowReordering(this) || commonColumnSettings.allowGrouping || commonColumnSettings.allowHiding)
},
init: function() {
var that = this;
this.callBase();
this._controller = this.getController("draggingHeader");
this._columnsResizerViewController = this.getController("columnsResizer");
this.getController("data").loadingChanged.add(function(isLoading) {
var element = that.element();
if (!isLoading && element) {
element.hide()
}
})
},
dragHeader: function(options) {
var that = this,
columnElement = options.columnElement;
that._isDragging = true;
that._dragOptions = options;
that._dropOptions = {
sourceIndex: options.index,
sourceColumnIndex: that._getVisibleIndexObject(options.rowIndex, options.columnIndex),
sourceColumnElement: options.columnElement,
sourceLocation: options.sourceLocation
};
var document = domAdapter.getDocument();
that._onSelectStart = document.onselectstart;
document.onselectstart = function() {
return false
};
that._controller.drag(that._dropOptions);
that.element().css({
textAlign: columnElement && columnElement.css("textAlign"),
height: columnElement && columnElement.height(),
width: columnElement && columnElement.width(),
whiteSpace: columnElement && columnElement.css("whiteSpace")
}).addClass(that.addWidgetPrefix(HEADERS_DRAG_ACTION_CLASS)).text(options.sourceColumn.caption);
that.element().appendTo($("body"))
},
moveHeader: function(args) {
var newLeft, newTop, moveDeltaX, moveDeltaY, e = args.event,
that = e.data.that,
eventData = eventUtils.eventData(e),
isResizing = that._columnsResizerViewController ? that._columnsResizerViewController.isResizing() : false,
dragOptions = that._dragOptions;
if (that._isDragging && !isResizing) {
var $element = that.element();
moveDeltaX = Math.abs(eventData.x - dragOptions.columnElement.offset().left - dragOptions.deltaX);
moveDeltaY = Math.abs(eventData.y - dragOptions.columnElement.offset().top - dragOptions.deltaY);
if ($element.is(":visible") || moveDeltaX > DRAGGING_DELTA || moveDeltaY > DRAGGING_DELTA) {
$element.show();
newLeft = eventData.x - dragOptions.deltaX;
newTop = eventData.y - dragOptions.deltaY;
$element.css({
left: newLeft,
top: newTop
});
that.dockHeader(eventData)
}
e.preventDefault()
}
},
dockHeader: function(eventData) {
var i, centerPosition, that = this,
targetDraggingPanel = that._getDraggingPanelByPos(eventData),
controller = that._controller,
params = that._dropOptions;
if (targetDraggingPanel) {
var rtlEnabled = that.option("rtlEnabled"),
isVerticalOrientation = "columnChooser" === targetDraggingPanel.getName(),
axisName = isVerticalOrientation ? "y" : "x",
targetLocation = targetDraggingPanel.getName(),
rowIndex = "headers" === targetLocation ? that._dragOptions.rowIndex : void 0,
sourceColumn = that._dragOptions.sourceColumn,
columnElements = targetDraggingPanel.getColumnElements(rowIndex, sourceColumn && sourceColumn.ownerBand) || [],
pointsByColumns = "columnChooser" === targetLocation ? [] : controller._generatePointsByColumns(extend({}, that._dragOptions, {
targetDraggingPanel: targetDraggingPanel,
columns: targetDraggingPanel.getColumns(rowIndex),
columnElements: columnElements,
isVerticalOrientation: isVerticalOrientation,
startColumnIndex: "headers" === targetLocation && $(columnElements[0]).index()
}));
params.targetLocation = targetLocation;
if (pointsByColumns.length > 0) {
for (i = 0; i < pointsByColumns.length; i++) {
centerPosition = pointsByColumns[i + 1] && (pointsByColumns[i][axisName] + pointsByColumns[i + 1][axisName]) / 2;
if (void 0 === centerPosition || (rtlEnabled && "x" === axisName ? eventData[axisName] > centerPosition : eventData[axisName] < centerPosition)) {
params.targetColumnIndex = that._getVisibleIndexObject(rowIndex, pointsByColumns[i].columnIndex);
if (columnElements[i]) {
params.targetColumnElement = columnElements.eq(i);
params.isLast = false
} else {
params.targetColumnElement = columnElements.last();
params.isLast = true
}
params.posX = pointsByColumns[i].x;
params.posY = pointsByColumns[i].y;
controller.dock(params);
break
}
}
} else {
that._resetTargetColumnOptions();
controller.dock(params)
}
}
},
dropHeader: function(args) {
var e = args.event,
that = e.data.that,
controller = that._controller;
that.element().hide();
if (controller && that._isDragging) {
controller.drop(that._dropOptions)
}
that.element().appendTo(that._parentElement());
that._dragOptions = null;
that._dropOptions = null;
that._isDragging = false;
domAdapter.getDocument().onselectstart = that._onSelectStart || null
}
});
var isNextColumnResizingMode = function(that) {
return "widget" !== that.option("columnResizingMode")
};
var ColumnsResizerViewController = modules.ViewController.inherit({
_isHeadersRowArea: function(posY) {
if (this._columnHeadersView) {
var headersRowHeight, offsetTop, element = this._columnHeadersView.element();
if (element) {
offsetTop = element.offset().top;
headersRowHeight = this._columnHeadersView.getHeadersRowHeight();
return posY >= offsetTop && posY <= offsetTop + headersRowHeight
}
}
return false
},
_pointCreated: function(point, cellsLength, columns) {
var currentColumn, nextColumn, isNextColumnMode = isNextColumnResizingMode(this),
rtlEnabled = this.option("rtlEnabled"),
firstPointColumnIndex = !isNextColumnMode && rtlEnabled ? 0 : 1;
if (point.index >= firstPointColumnIndex && point.index < cellsLength + (!isNextColumnMode && !rtlEnabled ? 1 : 0)) {
point.columnIndex -= firstPointColumnIndex;
currentColumn = columns[point.columnIndex] || {};
nextColumn = columns[point.columnIndex + 1] || {};
return !(isNextColumnMode ? currentColumn.allowResizing && nextColumn.allowResizing : currentColumn.allowResizing)
}
return true
},
_getTargetPoint: function(pointsByColumns, currentX, deltaX) {
if (pointsByColumns) {
for (var i = 0; i < pointsByColumns.length; i++) {
if (pointsByColumns[i].x === pointsByColumns[0].x && pointsByColumns[i + 1] && pointsByColumns[i].x === pointsByColumns[i + 1].x) {
continue
}
if (pointsByColumns[i].x - deltaX <= currentX && currentX <= pointsByColumns[i].x + deltaX) {
return pointsByColumns[i]
}
}
}
return null
},
_moveSeparator: function(args) {
var e = args.event,
that = e.data,
columnsSeparatorWidth = that._columnsSeparatorView.width(),
columnsSeparatorOffset = that._columnsSeparatorView.element().offset(),
isNextColumnMode = isNextColumnResizingMode(that),
deltaX = columnsSeparatorWidth / 2,
parentOffset = that._$parentContainer.offset(),
parentOffsetLeft = parentOffset.left,
eventData = eventUtils.eventData(e);
if (that._isResizing && that._resizingInfo) {
if (parentOffsetLeft <= eventData.x && (!isNextColumnMode || eventData.x <= parentOffsetLeft + that._$parentContainer.width())) {
if (that._updateColumnsWidthIfNeeded(eventData.x)) {
var $cell = that._columnHeadersView.getColumnElements().eq(that._resizingInfo.currentColumnIndex);
that._columnsSeparatorView.moveByX($cell.offset().left + (isNextColumnMode && that.option("rtlEnabled") ? 0 : $cell.outerWidth()));
that._tablePositionController.update(that._targetPoint.y);
e.preventDefault()
}
}
} else {
if (that._isHeadersRowArea(eventData.y)) {
if (that._previousParentOffset) {
if (that._previousParentOffset.left !== parentOffset.left || that._previousParentOffset.top !== parentOffset.top) {
that.pointsByColumns(null)
}
}
that._targetPoint = that._getTargetPoint(that.pointsByColumns(), eventData.x, columnsSeparatorWidth);
that._previousParentOffset = parentOffset;
that._isReadyResizing = false;
if (that._targetPoint && that._targetPoint.y <= eventData.y && columnsSeparatorOffset.top + that._columnsSeparatorView.height() >= eventData.y) {
that._columnsSeparatorView.changeCursor("col-resize");
that._columnsSeparatorView.moveByX(that._targetPoint.x - deltaX);
that._tablePositionController.update(that._targetPoint.y);
that._isReadyResizing = true;
e.preventDefault()
} else {
that._columnsSeparatorView.changeCursor()
}
} else {
that.pointsByColumns(null);
that._isReadyResizing = false;
that._columnsSeparatorView.changeCursor()
}
}
},
_endResizing: function(args) {
var e = args.event,
that = e.data;
if (that._isResizing) {
that.pointsByColumns(null);
that._resizingInfo = null;
that._columnsSeparatorView.hide();
that._columnsSeparatorView.changeCursor();
that._trackerView.hide();
if (!isNextColumnResizingMode(that)) {
var pageIndex = that.component.pageIndex();
that.component.updateDimensions();
if (that.option("wordWrapEnabled") && "virtual" === that.option("scrolling.mode")) {
that.component.refresh().done(function() {
that._rowsView.scrollToPage(pageIndex)
})
}
}
that._isReadyResizing = false;
that._isResizing = false
}
},
_getNextColumnIndex: function(currentColumnIndex) {
return currentColumnIndex + 1
},
_setupResizingInfo: function(posX) {
var that = this,
currentColumnIndex = that._targetPoint.columnIndex,
nextColumnIndex = that._getNextColumnIndex(currentColumnIndex),
currentHeader = that._columnHeadersView.getHeaderElement(currentColumnIndex),
nextHeader = that._columnHeadersView.getHeaderElement(nextColumnIndex);
that._resizingInfo = {
startPosX: posX,
currentColumnIndex: currentColumnIndex,
currentColumnWidth: currentHeader && currentHeader.length > 0 ? currentHeader.outerWidth() : 0,
nextColumnIndex: nextColumnIndex,
nextColumnWidth: nextHeader && nextHeader.length > 0 ? nextHeader.outerWidth() : 0
}
},
_startResizing: function(args) {
var e = args.event,
that = e.data,
eventData = eventUtils.eventData(e),
editingController = that.getController("editing"),
editingMode = that.option("editing.mode"),
isCellEditing = editingController.isEditing() && ("batch" === editingMode || "cell" === editingMode);
if (eventUtils.isTouchEvent(e)) {
if (that._isHeadersRowArea(eventData.y)) {
that._targetPoint = that._getTargetPoint(that.pointsByColumns(), eventData.x, COLUMNS_SEPARATOR_TOUCH_TRACKER_WIDTH);
if (that._targetPoint) {
that._columnsSeparatorView.moveByX(that._targetPoint.x - that._columnsSeparatorView.width() / 2);
that._isReadyResizing = true
}
} else {
that._isReadyResizing = false
}
}
if (that._isReadyResizing && !isCellEditing) {
that._setupResizingInfo(eventData.x);
that._tablePositionController.update(that._targetPoint.y);
that._columnsSeparatorView.show();
that._trackerView.show();
that._isResizing = true;
e.preventDefault();
e.stopPropagation()
}
},
_generatePointsByColumns: function() {
var that = this,
columns = that._columnsController ? that._columnsController.getVisibleColumns() : [],
cells = that._columnHeadersView.getColumnElements(),
pointsByColumns = [];
if (cells && cells.length > 0) {
pointsByColumns = gridCoreUtils.getPointsByColumns(cells, function(point) {
return that._pointCreated(point, cells.length, columns)
})
}
that._pointsByColumns = pointsByColumns
},
_unsubscribeFromEvents: function() {
this._moveSeparatorHandler && eventsEngine.off(domAdapter.getDocument(), addNamespace(pointerEvents.move, MODULE_NAMESPACE), this._moveSeparatorHandler);
this._startResizingHandler && eventsEngine.off(this._$parentContainer, addNamespace(pointerEvents.down, MODULE_NAMESPACE), this._startResizingHandler);
if (this._endResizingHandler) {
eventsEngine.off(this._columnsSeparatorView.element(), addNamespace(pointerEvents.up, MODULE_NAMESPACE), this._endResizingHandler);
eventsEngine.off(domAdapter.getDocument(), addNamespace(pointerEvents.up, MODULE_NAMESPACE), this._endResizingHandler)
}
},
_subscribeToEvents: function() {
this._moveSeparatorHandler = this.createAction(this._moveSeparator);
this._startResizingHandler = this.createAction(this._startResizing);
this._endResizingHandler = this.createAction(this._endResizing);
eventsEngine.on(domAdapter.getDocument(), addNamespace(pointerEvents.move, MODULE_NAMESPACE), this, this._moveSeparatorHandler);
eventsEngine.on(this._$parentContainer, addNamespace(pointerEvents.down, MODULE_NAMESPACE), this, this._startResizingHandler);
eventsEngine.on(this._columnsSeparatorView.element(), addNamespace(pointerEvents.up, MODULE_NAMESPACE), this, this._endResizingHandler);
eventsEngine.on(domAdapter.getDocument(), addNamespace(pointerEvents.up, MODULE_NAMESPACE), this, this._endResizingHandler)
},
_updateColumnsWidthIfNeeded: function(posX) {
var deltaX, nextCellWidth, column, minWidth, nextColumn, cellWidth, needUpdate = false,
columnsController = this._columnsController,
visibleColumns = columnsController.getVisibleColumns(),
columnsSeparatorWidth = this._columnsSeparatorView.width(),
contentWidth = this._rowsView.contentWidth(),
isNextColumnMode = isNextColumnResizingMode(this),
adaptColumnWidthByRatio = isNextColumnMode && this.option("adaptColumnWidthByRatio") && !this.option("columnAutoWidth");
function setColumnWidth(column, columnWidth, contentWidth, adaptColumnWidthByRatio) {
if (column) {
var oldColumnWidth = column.width;
if (oldColumnWidth) {
adaptColumnWidthByRatio = typeUtils.isString(oldColumnWidth) && "%" === oldColumnWidth.slice(-1)
}
if (adaptColumnWidthByRatio) {
column && columnsController.columnOption(column.index, "visibleWidth", columnWidth);
column && columnsController.columnOption(column.index, "width", (columnWidth / contentWidth * 100).toFixed(3) + "%")
} else {
column && columnsController.columnOption(column.index, "visibleWidth", void 0);
column && columnsController.columnOption(column.index, "width", columnWidth)
}
}
}
deltaX = posX - this._resizingInfo.startPosX;
if (isNextColumnMode && this.option("rtlEnabled")) {
deltaX = -deltaX
}
cellWidth = this._resizingInfo.currentColumnWidth + deltaX;
column = visibleColumns[this._resizingInfo.currentColumnIndex];
minWidth = column && column.minWidth || columnsSeparatorWidth;
needUpdate = cellWidth >= minWidth;
if (isNextColumnMode) {
nextCellWidth = this._resizingInfo.nextColumnWidth - deltaX;
nextColumn = visibleColumns[this._resizingInfo.nextColumnIndex];
minWidth = nextColumn && nextColumn.minWidth || columnsSeparatorWidth;
needUpdate = needUpdate && nextCellWidth >= minWidth
}
if (needUpdate) {
columnsController.beginUpdate();
cellWidth = Math.floor(cellWidth);
setColumnWidth(column, cellWidth, contentWidth, adaptColumnWidthByRatio);
if (isNextColumnMode) {
nextCellWidth = Math.floor(nextCellWidth);
setColumnWidth(nextColumn, nextCellWidth, contentWidth, adaptColumnWidthByRatio)
} else {
var columnWidths = this._columnHeadersView.getColumnWidths();
for (var i = 0; i < columnWidths.length; i++) {
if (visibleColumns[i] && visibleColumns[i] !== column && void 0 === visibleColumns[i].width) {
columnsController.columnOption(visibleColumns[i].index, "width", columnWidths[i])
}
}
}
columnsController.endUpdate()
}
return needUpdate
},
_subscribeToCallback: function(callback, handler) {
callback.add(handler);
this._subscribesToCallbacks.push({
callback: callback,
handler: handler
})
},
_unsubscribeFromCallbacks: function() {
var i, subscribe;
for (i = 0; i < this._subscribesToCallbacks.length; i++) {
subscribe = this._subscribesToCallbacks[i];
subscribe.callback.remove(subscribe.handler)
}
this._subscribesToCallbacks = []
},
_unsubscribes: function() {
this._unsubscribeFromEvents();
this._unsubscribeFromCallbacks()
},
_init: function() {
var that = this,
generatePointsByColumnsHandler = function() {
if (!that._isResizing) {
that.pointsByColumns(null)
}
},
generatePointsByColumnsScrollHandler = function(offset) {
if (that._scrollLeft !== offset.left) {
that._scrollLeft = offset.left;
that.pointsByColumns(null)
}
};
that._columnsSeparatorView = that.getView("columnsSeparatorView");
that._columnHeadersView = that.getView("columnHeadersView");
that._trackerView = that.getView("trackerView");
that._rowsView = that.getView("rowsView");
that._columnsController = that.getController("columns");
that._tablePositionController = that.getController("tablePosition");
that._$parentContainer = that._columnsSeparatorView.component.$element();
that._subscribeToCallback(that._columnHeadersView.renderCompleted, generatePointsByColumnsHandler);
that._subscribeToCallback(that._columnHeadersView.resizeCompleted, generatePointsByColumnsHandler);
that._subscribeToCallback(that._columnsSeparatorView.renderCompleted, function() {
that._unsubscribeFromEvents();
that._subscribeToEvents()
});
that._subscribeToCallback(that._rowsView.renderCompleted, function() {
that._rowsView.scrollChanged.remove(generatePointsByColumnsScrollHandler);
that._rowsView.scrollChanged.add(generatePointsByColumnsScrollHandler)
});
var previousScrollbarVisibility = 0 !== that._rowsView.getScrollbarWidth();
var previousTableHeight = 0;
that._subscribeToCallback(that.getController("tablePosition").positionChanged, function(e) {
if (that._isResizing && !that._rowsView.isResizing) {
var scrollbarVisibility = 0 !== that._rowsView.getScrollbarWidth();
if (previousScrollbarVisibility !== scrollbarVisibility || previousTableHeight && previousTableHeight !== e.height) {
previousScrollbarVisibility = scrollbarVisibility;
previousTableHeight = e.height;
that.component.updateDimensions()
} else {
that._rowsView.updateFreeSpaceRowHeight()
}
}
previousTableHeight = e.height
})
},
optionChanged: function(args) {
this.callBase(args);
if ("allowColumnResizing" === args.name) {
if (args.value) {
this._init();
this._subscribeToEvents()
} else {
this._unsubscribes()
}
}
},
isResizing: function() {
return this._isResizing
},
init: function() {
this._subscribesToCallbacks = [];
if (allowResizing(this)) {
this._init()
}
},
pointsByColumns: function(value) {
if (void 0 !== value) {
this._pointsByColumns = value
} else {
if (!this._pointsByColumns) {
this._generatePointsByColumns()
}
return this._pointsByColumns
}
},
dispose: function() {
this._unsubscribes();
this.callBase()
}
});
var TablePositionViewController = modules.ViewController.inherit({
update: function(top) {
var that = this,
$element = that._columnHeadersView.element(),
offset = $element && $element.offset(),
offsetTop = offset && offset.top || 0,
diffOffsetTop = typeUtils.isDefined(top) ? Math.abs(top - offsetTop) : 0,
columnsHeadersHeight = that._columnHeadersView ? that._columnHeadersView.getHeight() : 0,
rowsHeight = that._rowsView ? that._rowsView.height() - that._rowsView.getScrollbarWidth(true) : 0;
that.positionChanged.fire({
height: columnsHeadersHeight + rowsHeight - diffOffsetTop,
top: $element && $element.length && $element[0].offsetTop + diffOffsetTop
})
},
init: function() {
var that = this;
that.callBase();
that._columnHeadersView = this.getView("columnHeadersView");
that._rowsView = this.getView("rowsView");
that._pagerView = this.getView("pagerView");
that._rowsView.resizeCompleted.add(function() {
if (that.option("allowColumnResizing")) {
that.update()
}
})
},
ctor: function(component) {
this.callBase(component);
this.positionChanged = Callbacks()
}
});
var DraggingHeaderViewController = modules.ViewController.inherit({
_generatePointsByColumns: function(options) {
var that = this;
return gridCoreUtils.getPointsByColumns(options.columnElements, function(point) {
return that._pointCreated(point, options.columns, options.targetDraggingPanel.getName(), options.sourceColumn)
}, options.isVerticalOrientation, options.startColumnIndex)
},
_pointCreated: function(point, columns, location, sourceColumn) {
var targetColumn = columns[point.columnIndex],
prevColumn = columns[point.columnIndex - 1];
switch (location) {
case "columnChooser":
return true;
case "headers":
return sourceColumn && !sourceColumn.allowReordering || (!targetColumn || !targetColumn.allowReordering) && (!prevColumn || !prevColumn.allowReordering);
default:
return 0 === columns.length
}
},
_subscribeToEvents: function(draggingHeader, draggingPanels) {
var that = this;
each(draggingPanels, function(_, draggingPanel) {
if (draggingPanel) {
var i, columns, columnElements, rowCount = draggingPanel.getRowCount ? draggingPanel.getRowCount() : 1,
nameDraggingPanel = draggingPanel.getName(),
subscribeToEvents = function(index, columnElement) {
if (!columnElement) {
return
}
var $columnElement = $(columnElement),
column = columns[index];
if (draggingPanel.allowDragging(column, nameDraggingPanel, draggingPanels)) {
$columnElement.addClass(that.addWidgetPrefix(HEADERS_DRAG_ACTION_CLASS));
eventsEngine.on($columnElement, addNamespace(dragEvents.start, MODULE_NAMESPACE), that.createAction(function(args) {
var e = args.event,
eventData = eventUtils.eventData(e);
draggingHeader.dragHeader({
deltaX: eventData.x - $(e.currentTarget).offset().left,
deltaY: eventData.y - $(e.currentTarget).offset().top,
sourceColumn: column,
index: column.index,
columnIndex: index,
columnElement: $columnElement,
sourceLocation: nameDraggingPanel,
draggingPanels: draggingPanels,
rowIndex: that._columnsController.getRowIndex(column.index, true)
})
}));
eventsEngine.on($columnElement, addNamespace(dragEvents.move, MODULE_NAMESPACE), {
that: draggingHeader
}, that.createAction(draggingHeader.moveHeader));
eventsEngine.on($columnElement, addNamespace(dragEvents.end, MODULE_NAMESPACE), {
that: draggingHeader
}, that.createAction(draggingHeader.dropHeader))
}
};
for (i = 0; i < rowCount; i++) {
columnElements = draggingPanel.getColumnElements(i) || [];
if (columnElements.length) {
columns = draggingPanel.getColumns(i) || [];
each(columnElements, subscribeToEvents)
}
}
}
})
},
_unsubscribeFromEvents: function(draggingHeader, draggingPanels) {
var that = this;
each(draggingPanels, function(_, draggingPanel) {
if (draggingPanel) {
var columnElements = draggingPanel.getColumnElements() || [];
each(columnElements, function(index, columnElement) {
var $columnElement = $(columnElement);
eventsEngine.off($columnElement, addNamespace(dragEvents.start, MODULE_NAMESPACE));
eventsEngine.off($columnElement, addNamespace(dragEvents.move, MODULE_NAMESPACE));
eventsEngine.off($columnElement, addNamespace(dragEvents.end, MODULE_NAMESPACE));
$columnElement.removeClass(that.addWidgetPrefix(HEADERS_DRAG_ACTION_CLASS))
})
}
})
},
_getSeparator: function(targetLocation) {
return "headers" === targetLocation ? this._columnsSeparatorView : this._blockSeparatorView
},
hideSeparators: function() {
var blockSeparator = this._blockSeparatorView,
columnsSeparator = this._columnsSeparatorView;
this._animationColumnIndex = null;
blockSeparator && blockSeparator.hide();
columnsSeparator && columnsSeparator.hide()
},
init: function() {
var subscribeToEvents, that = this;
that.callBase();
that._columnsController = that.getController("columns");
that._columnHeadersView = that.getView("columnHeadersView");
that._columnsSeparatorView = that.getView("columnsSeparatorView");
that._draggingHeaderView = that.getView("draggingHeaderView");
that._rowsView = that.getView("rowsView");
that._blockSeparatorView = that.getView("blockSeparatorView");
that._headerPanelView = that.getView("headerPanel");
that._columnChooserView = that.getView("columnChooserView");
subscribeToEvents = function() {
if (that._draggingHeaderView) {
var draggingPanels = [that._columnChooserView, that._columnHeadersView, that._headerPanelView];
that._unsubscribeFromEvents(that._draggingHeaderView, draggingPanels);
that._subscribeToEvents(that._draggingHeaderView, draggingPanels)
}
};
that._columnHeadersView.renderCompleted.add(subscribeToEvents);
that._headerPanelView && that._headerPanelView.renderCompleted.add(subscribeToEvents);
that._columnChooserView && that._columnChooserView.renderCompleted.add(subscribeToEvents)
},
allowDrop: function(parameters) {
return this._columnsController.allowMoveColumn(parameters.sourceColumnIndex, parameters.targetColumnIndex, parameters.sourceLocation, parameters.targetLocation)
},
drag: function(parameters) {
var sourceIndex = parameters.sourceIndex,
sourceLocation = parameters.sourceLocation,
sourceColumnElement = parameters.sourceColumnElement,
headersView = this._columnHeadersView,
rowsView = this._rowsView;
if (sourceColumnElement) {
sourceColumnElement.css({
opacity: COLUMN_OPACITY
});
if ("headers" === sourceLocation) {
headersView && headersView.setRowsOpacity(sourceIndex, COLUMN_OPACITY);
rowsView && rowsView.setRowsOpacity(sourceIndex, COLUMN_OPACITY)
}
}
},
dock: function(parameters) {
var that = this,
targetColumnIndex = typeUtils.isObject(parameters.targetColumnIndex) ? parameters.targetColumnIndex.columnIndex : parameters.targetColumnIndex,
sourceLocation = parameters.sourceLocation,
targetLocation = parameters.targetLocation,
separator = that._getSeparator(targetLocation),
hasTargetVisibleIndex = targetColumnIndex >= 0;
var showSeparator = function() {
if (that._animationColumnIndex !== targetColumnIndex) {
that.hideSeparators();
separator.element()[parameters.isLast ? "insertAfter" : "insertBefore"](parameters.targetColumnElement);
that._animationColumnIndex = targetColumnIndex;
separator.show(targetLocation)
}
};
that._columnHeadersView.element().find("." + HEADER_ROW_CLASS).toggleClass(that.addWidgetPrefix(HEADERS_DROP_HIGHLIGHT_CLASS), "headers" !== sourceLocation && "headers" === targetLocation && !hasTargetVisibleIndex);
if (separator) {
if (that.allowDrop(parameters) && hasTargetVisibleIndex) {
if ("group" === targetLocation || "columnChooser" === targetLocation) {
showSeparator()
} else {
that.hideSeparators();
that.getController("tablePosition").update(parameters.posY);
separator.moveByX(parameters.posX - separator.width());
separator.show()
}
} else {
that.hideSeparators()
}
}
},
drop: function(parameters) {
var sourceColumnElement = parameters.sourceColumnElement;
if (sourceColumnElement) {
sourceColumnElement.css({
opacity: ""
});
this._columnHeadersView.setRowsOpacity(parameters.sourceIndex, "");
this._rowsView.setRowsOpacity(parameters.sourceIndex, "");
this._columnHeadersView.element().find("." + HEADER_ROW_CLASS).removeClass(this.addWidgetPrefix(HEADERS_DROP_HIGHLIGHT_CLASS))
}
if (this.allowDrop(parameters)) {
var separator = this._getSeparator(parameters.targetLocation);
if (separator) {
separator.hide()
}
this._columnsController.moveColumn(parameters.sourceColumnIndex, parameters.targetColumnIndex, parameters.sourceLocation, parameters.targetLocation)
}
},
dispose: function() {
if (this._draggingHeaderView) {
this._unsubscribeFromEvents(this._draggingHeaderView, [this._columnChooserView, this._columnHeadersView, this._headerPanelView]);
}
}
});
module.exports = {
views: {
columnsSeparatorView: ColumnsSeparatorView,
blockSeparatorView: BlockSeparatorView,
draggingHeaderView: DraggingHeaderView,
trackerView: TrackerView
},
controllers: {
draggingHeader: DraggingHeaderViewController,
tablePosition: TablePositionViewController,
columnsResizer: ColumnsResizerViewController
},
extenders: {
views: {
rowsView: {
_needUpdateRowHeight: function(itemCount) {
var wordWrapEnabled = this.option("wordWrapEnabled"),
columnsResizerController = this.getController("columnsResizer"),
isResizing = columnsResizerController.isResizing();
return this.callBase.apply(this, arguments) || itemCount > 0 && wordWrapEnabled && isResizing
}
}
}
}
};