Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

slickgrid

Package Overview
Dependencies
Maintainers
2
Versions
123
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

slickgrid - npm Package Compare versions

Comparing version 2.4.0 to 2.4.1

.gitattributes

54

controls/slick.columnpicker.js

@@ -19,2 +19,3 @@ /***

* forceFitTitle: "Force fit columns", // default to "Force fit columns"
* headerColumnValueExtractor: "Extract the column label" // default to column.name
* syncResizeTitle: "Synchronous resize", // default to "Synchronous resize"

@@ -32,2 +33,3 @@ * }

function SlickColumnPicker(columns, grid, options) {
var _grid = grid;
var $list;

@@ -45,6 +47,10 @@ var $menu;

forceFitTitle: "Force fit columns",
syncResizeTitle: "Synchronous resize"
syncResizeTitle: "Synchronous resize",
headerColumnValueExtractor:
function (columnDef) {
return columnDef.name;
}
};
function init() {
function init(grid) {
grid.onHeaderContextMenu.subscribe(handleHeaderContextMenu);

@@ -75,4 +81,4 @@ grid.onColumnsReordered.subscribe(updateColumnOrder);

function destroy() {
grid.onHeaderContextMenu.unsubscribe(handleHeaderContextMenu);
grid.onColumnsReordered.unsubscribe(updateColumnOrder);
_grid.onHeaderContextMenu.unsubscribe(handleHeaderContextMenu);
_grid.onColumnsReordered.unsubscribe(updateColumnOrder);
$(document.body).off("mousedown", handleBodyMouseDown);

@@ -96,2 +102,3 @@ $("div.slick-columnpicker").hide(options.fadeSpeed);

var $li, $input;
var columnLabel;
for (var i = 0; i < columns.length; i++) {

@@ -102,10 +109,16 @@ $li = $("<li />").appendTo($list);

if (grid.getColumnIndex(columns[i].id) != null) {
if (_grid.getColumnIndex(columns[i].id) != null) {
$input.attr("checked", "checked");
}
if (options.columnPicker.headerColumnValueExtractor) {
columnLabel = options.columnPicker.headerColumnValueExtractor(columns[i]);
} else {
columnLabel = defaults.headerColumnValueExtractor(columns[i]);
}
$("<label />")
.html(columns[i].name)
.prepend($input)
.appendTo($li);
.html(columnLabel)
.prepend($input)
.appendTo($li);
}

@@ -125,3 +138,3 @@

.appendTo($li);
if (grid.getOptions().forceFitColumns) {
if (_grid.getOptions().forceFitColumns) {
$input.attr("checked", "checked");

@@ -139,3 +152,3 @@ }

.appendTo($li);
if (grid.getOptions().syncColumnCellResize) {
if (_grid.getOptions().syncColumnCellResize) {
$input.attr("checked", "checked");

@@ -161,6 +174,6 @@ }

// of the current column sort.
var current = grid.getColumns().slice(0);
var current = _grid.getColumns().slice(0);
var ordered = new Array(columns.length);
for (var i = 0; i < ordered.length; i++) {
if ( grid.getColumnIndex(columns[i].id) === undefined ) {
if ( _grid.getColumnIndex(columns[i].id) === undefined ) {
// If the column doesn't return a value from getColumnIndex,

@@ -180,6 +193,6 @@ // it is hidden. Leave it in this position.

if (e.target.checked) {
grid.setOptions({forceFitColumns:true});
grid.autosizeColumns();
_grid.setOptions({forceFitColumns:true});
_grid.autosizeColumns();
} else {
grid.setOptions({forceFitColumns:false});
_grid.setOptions({forceFitColumns:false});
}

@@ -191,5 +204,5 @@ return;

if (e.target.checked) {
grid.setOptions({syncColumnCellResize:true});
_grid.setOptions({syncColumnCellResize:true});
} else {
grid.setOptions({syncColumnCellResize:false});
_grid.setOptions({syncColumnCellResize:false});
}

@@ -212,4 +225,4 @@ return;

grid.setColumns(visibleColumns);
onColumnsChanged.notify({columns: visibleColumns, grid: grid});
_grid.setColumns(visibleColumns);
onColumnsChanged.notify({columns: visibleColumns, grid: _grid});
}

@@ -222,5 +235,6 @@ }

init();
init(_grid);
return {
"init": init,
"getAllColumns": getAllColumns,

@@ -227,0 +241,0 @@ "destroy": destroy,

@@ -22,3 +22,3 @@ /***

* menuWidth: 18, // width that will be use to resize the column header container (18 by default)
* resizeOnShowHeaderRow: true, // true by default
* resizeOnShowHeaderRow: false, // false by default
*

@@ -98,2 +98,4 @@ * // the last 2 checkboxes titles

var _grid = grid;
var _gridOptions;
var _gridUid = (grid && grid.getUID) ? grid.getUID() : '';
var _isMenuOpen = false;

@@ -103,2 +105,3 @@ var _options = options;

var $list;
var $button;
var $menu;

@@ -108,3 +111,3 @@ var columnCheckboxes;

hideForceFitButton: false,
hideSyncResizeButton: false,
hideSyncResizeButton: false,
fadeSpeed: 250,

@@ -118,14 +121,23 @@ forceFitTitle: "Force fit columns",

function init(grid) {
_gridOptions = grid.getOptions();
var gridMenuWidth = (_options.gridMenu && _options.gridMenu.menuWidth) || _defaults.menuWidth;
var $header = $('.slick-header');
var $header;
if (_gridOptions && _gridOptions.frozenColumn && _gridOptions.frozenColumn > 0 ) {
$header = $('.' + _gridUid + ' .slick-header-right');
} else {
$header = $('.' + _gridUid + ' .slick-header-left');
}
$header.attr('style', 'width: calc(100% - ' + gridMenuWidth +'px)');
// subscribe to the grid, when it's destroyed, we should also destroy the Grid Menu
grid.onBeforeDestroy.subscribe(destroy);
// if header row is enabled, we need to resize it's width also
var enableResizeHeaderRow = (_options.gridMenu && _options.gridMenu.resizeOnShowHeaderRow != undefined) ? _options.gridMenu.resizeOnShowHeaderRow : _defaults.resizeOnShowHeaderRow;
if(enableResizeHeaderRow) {
var $headerrow = $('.slick-headerrow');
if(enableResizeHeaderRow && _options.showHeaderRow) {
var $headerrow = $('.' + _gridUid + '.slick-headerrow');
$headerrow.attr('style', 'width: calc(100% - ' + gridMenuWidth +'px)');
}
var $button = $('<button class="slick-gridmenu-button"/>');
$button = $('<button class="slick-gridmenu-button"/>');
if (_options.gridMenu && _options.gridMenu.iconCssClass) {

@@ -156,3 +168,3 @@ $button.addClass(_options.gridMenu.iconCssClass);

// Hide the menu on outside click.
$(document.body).on("mousedown", handleBodyMouseDown);
$(document.body).on("mousedown." + _gridUid, handleBodyMouseDown);

@@ -163,3 +175,3 @@ // destroy the picker if user leaves the page

// add on click handler for the Grid Menu itself
$button.on("click", showGridMenu);
$button.on("click." + _gridUid, showGridMenu);
}

@@ -173,5 +185,7 @@

_grid.onColumnsReordered.unsubscribe(updateColumnOrder);
$(document.body).off("mousedown", handleBodyMouseDown);
_grid.onBeforeDestroy.unsubscribe();
$(document.body).off("mousedown." + _gridUid, handleBodyMouseDown);
$("div.slick-gridmenu").hide(_options.fadeSpeed);
$menu.remove();
$button.remove();
}

@@ -306,2 +320,3 @@

$list.appendTo($menu);
_isMenuOpen = true;
}

@@ -312,4 +327,2 @@

hideMenu(e);
} else {
_isMenuOpen = true;
}

@@ -316,0 +329,0 @@ }

{
"name": "slickgrid",
"version": "2.4.0",
"version": "2.4.1",
"description": "A lightning fast JavaScript grid/spreadsheet",

@@ -5,0 +5,0 @@ "main": "slick.core.js",

@@ -31,2 +31,3 @@ (function ($) {

readOnlyMode: suppresses paste
headerColumnValueExtractor : option to specify a custom column header value extractor function
*/

@@ -71,8 +72,17 @@ var _grid;

function getDataItemValueForColumn(item, columnDef) {
function getHeaderValueForColumn(columnDef) {
if (_options.headerColumnValueExtractor) {
var val = _options.headerColumnValueExtractor(columnDef);
if (val) { return val; }
}
return columnDef.name;
}
function getDataItemValueForColumn(item, columnDef, e) {
if (_options.dataItemColumnValueExtractor) {
var dataItemColumnValueExtractorValue = _options.dataItemColumnValueExtractor(item, columnDef);
var val = _options.dataItemColumnValueExtractor(item, columnDef);
if (dataItemColumnValueExtractorValue)
return dataItemColumnValueExtractorValue;
if (val) { return val; }
}

@@ -88,3 +98,4 @@

'position':{'top':0, 'left':0}, // a dummy position required by some editors
'grid':_grid
'grid':_grid,
'event':e
};

@@ -354,3 +365,3 @@ var editor = new columnDef.editor(editorArgs);

if (columns[j].name.length > 0)
clipTextHeaders.push(columns[j].name);
clipTextHeaders.push(getHeaderValueForColumn(columns[j]));
}

@@ -361,3 +372,3 @@ clipTextRows.push(clipTextHeaders.join("\t"));

for (var j=range.fromCell; j< range.toCell+1 ; j++){
clipTextCells.push(getDataItemValueForColumn(dt, columns[j]));
clipTextCells.push(getDataItemValueForColumn(dt, columns[j], e));
}

@@ -446,2 +457,6 @@ clipTextRows.push(clipTextCells.join("\t"));

function setIncludeHeaderWhenCopying(includeHeaderWhenCopying) {
_options.includeHeaderWhenCopying = includeHeaderWhenCopying;
}
$.extend(this, {

@@ -455,5 +470,6 @@ "init": init,

"onCopyCancelled": new Slick.Event(),
"onPasteCells": new Slick.Event()
"onPasteCells": new Slick.Event(),
"setIncludeHeaderWhenCopying" : setIncludeHeaderWhenCopying
});
}
})(jQuery);
})(jQuery);

@@ -44,3 +44,3 @@ (function ($) {

.css("position", "absolute")
.appendTo(grid.getCanvasNode());
.appendTo(grid.getActiveCanvasNode());
}

@@ -47,0 +47,0 @@

@@ -13,2 +13,4 @@ (function ($) {

var _canvas;
var _gridOptions;
var _$activeCanvas;
var _dragging;

@@ -24,2 +26,8 @@ var _decorator;

// Frozen row & column variables
var _rowOffset;
var _columnOffset;
var _isRightCanvas;
var _isBottomCanvas;
function init(grid) {

@@ -30,2 +38,3 @@ options = $.extend(true, {}, _defaults, options);

_canvas = _grid.getCanvasNode();
_gridOptions = _grid.getOptions();
_handler

@@ -47,2 +56,22 @@ .subscribe(_grid.onDragInit, handleDragInit)

function handleDragInit(e, dd) {
// Set the active canvas node because the decorator needs to append its
// box to the correct canvas
_$activeCanvas = $( _grid.getActiveCanvasNode( e ) );
var c = _$activeCanvas.offset();
_rowOffset = 0;
_columnOffset = 0;
_isBottomCanvas = _$activeCanvas.hasClass( 'grid-canvas-bottom' );
if ( _gridOptions.frozenRow > -1 && _isBottomCanvas ) {
_rowOffset = ( _gridOptions.frozenBottom ) ? $('.grid-canvas-bottom').height() : $('.grid-canvas-top').height();
}
_isRightCanvas = _$activeCanvas.hasClass( 'grid-canvas-right' );
if ( _gridOptions.frozenColumn > -1 && _isRightCanvas ) {
_columnOffset = $('.grid-canvas-left').width();
}
// prevent the grid from cancelling drag'n'drop by default

@@ -82,11 +111,24 @@ e.stopImmediatePropagation();

var end = _grid.getCellFromPoint(
e.pageX - $(_canvas).offset().left,
e.pageY - $(_canvas).offset().top);
e.pageX - _$activeCanvas.offset().left + _columnOffset,
e.pageY - _$activeCanvas.offset().top + _rowOffset
);
if (!_grid.canCellBeSelected(end.row, end.cell)) {
return;
if (_gridOptions.frozenColumn < 0) {
if (!_grid.canCellBeSelected(end.row, end.cell)) {
return;
}
} else {
// when having frozen column(s), we need to do extra checks
if ( (!_grid.canCellBeSelected( end.row, end.cell ) )
|| ( !_isRightCanvas && ( end.cell > _gridOptions.frozenColumn ) )
|| ( _isRightCanvas && ( end.cell <= _gridOptions.frozenColumn ) )
|| ( !_isBottomCanvas && ( end.row >= _gridOptions.frozenRow ) )
|| ( _isBottomCanvas && ( end.row < _gridOptions.frozenRow ) )
) {
return;
}
}
dd.range.end = end;
_currentlySelectedRange = dd.range;
_decorator.show(new Slick.Range(dd.range.start.row, dd.range.start.cell, end.row, end.cell));

@@ -128,2 +170,2 @@ }

}
})(jQuery);
})(jQuery);

@@ -63,2 +63,20 @@ (function ($) {

function rangesAreEqual(range1, range2) {
var areDifferent = (range1.length !== range2.length);
if (!areDifferent) {
for (var i = 0; i < range1.length; i++) {
if (
range1[i].fromCell !== range2[i].fromCell
|| range1[i].fromRow !== range2[i].fromRow
|| range1[i].toCell !== range2[i].toCell
|| range1[i].toRow !== range2[i].toRow
) {
areDifferent = true;
break;
}
}
}
return !areDifferent;
}
function setSelectedRanges(ranges) {

@@ -68,4 +86,7 @@ // simple check for: empty selection didn't change, prevent firing onSelectedRangesChanged

// if range has not changed, don't fire onSelectedRangesChanged
var rangeHasChanged = !rangesAreEqual(_ranges, ranges);
_ranges = removeInvalidRanges(ranges);
_self.onSelectedRangesChanged.notify(_ranges);
if (rangeHasChanged) { _self.onSelectedRangesChanged.notify(_ranges); }
}

@@ -72,0 +93,0 @@

@@ -12,3 +12,3 @@ (function ($) {

var _grid;
var _self = this;
var _selectAll_UID = createUID();
var _handler = new Slick.EventHandler();

@@ -19,5 +19,9 @@ var _selectedRowsLookup = {};

cssClass: null,
hideSelectAllCheckbox: false,
toolTip: "Select/Deselect All",
width: 30
width: 30,
hideInColumnTitleRow: false,
hideInFilterHeaderRow: true
};
var _isSelectAllChecked = false;

@@ -29,6 +33,12 @@ var _options = $.extend(true, {}, _defaults, options);

_handler
.subscribe(_grid.onSelectedRowsChanged, handleSelectedRowsChanged)
.subscribe(_grid.onClick, handleClick)
.subscribe(_grid.onHeaderClick, handleHeaderClick)
.subscribe(_grid.onKeyDown, handleKeyDown);
.subscribe(_grid.onSelectedRowsChanged, handleSelectedRowsChanged)
.subscribe(_grid.onClick, handleClick)
.subscribe(_grid.onKeyDown, handleKeyDown);
if (!_options.hideInFilterHeaderRow) {
addCheckboxToFilterHeaderRow(grid);
}
if (!_options.hideInColumnTitleRow) {
_handler.subscribe(_grid.onHeaderClick, handleHeaderClick)
}
}

@@ -40,4 +50,43 @@

function getOptions() {
return _options;
}
function setOptions(options) {
_options = $.extend(true, {}, _options, options);
if (_options.hideSelectAllCheckbox) {
hideSelectAllFromColumnHeaderTitleRow();
hideSelectAllFromColumnHeaderFilterRow();
} else {
if (!_options.hideInColumnTitleRow) {
if (_isSelectAllChecked) {
_grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox' checked='checked'><label for='header-selector" + _selectAll_UID + "'></label>", _options.toolTip);
} else {
_grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox'><label for='header-selector" + _selectAll_UID + "'></label>", _options.toolTip);
}
_handler.subscribe(_grid.onHeaderClick, handleHeaderClick);
} else {
hideSelectAllFromColumnHeaderTitleRow();
}
if (!_options.hideInFilterHeaderRow) {
var selectAllContainer = $("#filter-checkbox-selectall-container");
selectAllContainer.show();
selectAllContainer.find('input[type="checkbox"]').prop("checked", _isSelectAllChecked);
} else {
hideSelectAllFromColumnHeaderFilterRow();
}
}
}
function hideSelectAllFromColumnHeaderTitleRow() {
_grid.updateColumnHeader(_options.columnId, "", "");
}
function hideSelectAllFromColumnHeaderFilterRow() {
$("#filter-checkbox-selectall-container").hide();
}
function handleSelectedRowsChanged(e, args) {
var UID = createUID();
var selectedRows = _grid.getSelectedRows();

@@ -58,7 +107,14 @@ var lookup = {}, row, i;

_grid.render();
_isSelectAllChecked = selectedRows.length && selectedRows.length == _grid.getDataLength();
if (selectedRows.length && selectedRows.length == _grid.getDataLength()) {
_grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + UID + "' type='checkbox' checked='checked'><label for='header-selector" + UID + "'></label>", _options.toolTip);
} else {
_grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + UID + "' type='checkbox'><label for='header-selector" + UID + "'></label>", _options.toolTip);
if (!_options.hideInColumnTitleRow && !_options.hideSelectAllCheckbox) {
if (_isSelectAllChecked) {
_grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox' checked='checked'><label for='header-selector" + _selectAll_UID + "'></label>", _options.toolTip);
} else {
_grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox'><label for='header-selector" + _selectAll_UID + "'></label>", _options.toolTip);
}
}
if (!_options.hideInFilterHeaderRow) {
var selectAllElm = $("#header-filter-selector" + _selectAll_UID);
selectAllElm.prop("checked", _isSelectAllChecked);
}

@@ -169,7 +225,5 @@ }

function getColumnDefinition() {
var UID = createUID();
return {
id: _options.columnId,
name: "<input id='header-selector" + UID + "' type='checkbox'><label for='header-selector" + UID + "'></label>",
name: (_options.hideSelectAllCheckbox || _options.hideInColumnTitleRow) ? "" : "<input id='header-selector" + _selectAll_UID + "' type='checkbox'><label for='header-selector" + _selectAll_UID + "'></label>",
toolTip: _options.toolTip,

@@ -181,2 +235,3 @@ field: "sel",

cssClass: _options.cssClass,
hideSelectAllCheckbox: _options.hideSelectAllCheckbox,
formatter: checkboxSelectionFormatter

@@ -186,2 +241,15 @@ };

function addCheckboxToFilterHeaderRow(grid) {
grid.onHeaderRowCellRendered.subscribe(function(e, args) {
if (args.column.field === "sel") {
$(args.node).empty();
$("<span id='filter-checkbox-selectall-container'><input id='header-filter-selector" + _selectAll_UID + "' type='checkbox'><label for='header-filter-selector" + _selectAll_UID + "'></label></span>")
.appendTo(args.node)
.on('click', function(evnt) {
handleHeaderClick(evnt, args)
});
}
});
}
function createUID() {

@@ -207,5 +275,7 @@ return Math.round(10000000 * Math.random());

"selectRows": selectRows,
"getColumnDefinition": getColumnDefinition
"getColumnDefinition": getColumnDefinition,
"getOptions": getOptions,
"setOptions": setOptions,
});
}
})(jQuery);

@@ -19,9 +19,30 @@ /**

/**
* DraggableGrouping plugin to show/hide tooltips when columns are too narrow to fit content.
* @constructor
* @param {boolean} [options.enableForCells=true] - Enable tooltip for grid cells
* @param {boolean} [options.enableForHeaderCells=false] - Enable tooltip for header cells
* @param {number} [options.maxToolTipLength=null] - The maximum length for a tooltip
/***
* A plugin to add Draggable Grouping feature.
*
* USAGE:
*
* Add the plugin .js & .css files and register it with the grid.
*
*
* The plugin expose the following methods:
* destroy: used to destroy the plugin
* setDroppedGroups: provide option to set default grouping on loading
* clearDroppedGroups: provide option to clear grouping
* getSetupColumnReorder: its function to setup draggable feature agains Header Column, should be passed on grid option. Also possible to pass custom function
*
*
* The plugin expose the following event(s):
* onGroupChanged: pass the grouped columns to who subscribed.
*
* @param options {Object} Options:
* deleteIconCssClass: an extra CSS class to add to the delete button (default undefined), if deleteIconCssClass && deleteIconImage undefined then slick-groupby-remove-image class will be added
* deleteIconImage: a url to the delete button image (default undefined)
* groupIconCssClass: an extra CSS class to add to the grouping field hint (default undefined)
* groupIconImage: a url to the grouping field hint image (default undefined)
* dropPlaceHolderText: option to specify set own placeholder note text
*
*/
function DraggableGrouping(options) {

@@ -34,6 +55,8 @@ var _grid;

var dropboxPlaceholder;
var groupToggler;
var _self = this;
var _defaults = {
};
var onGroupChanged = new Slick.Event();
/**

@@ -50,8 +73,72 @@ * Initialize plugin.

dropbox = $(_grid.getPreHeaderPanel());
dropbox.html("<div class='slick-placeholder'>Drop a column header here to group by the column</div>");
var dropPlaceHolderText = options.dropPlaceHolderText || 'Drop a column header here to group by the column';
dropbox.html("<div class='slick-placeholder'>" + dropPlaceHolderText + "</div><div class='slick-group-toggle-all expanded' style='display:none'></div>");
dropboxPlaceholder = dropbox.find(".slick-placeholder");
dropboxPlaceholder = dropbox.find(".slick-placeholder");
groupToggler = dropbox.find(".slick-group-toggle-all");
setupColumnDropbox();
_grid.onHeaderCellRendered.subscribe(function (e, args) {
var column = args.column;
var node = args.node;
if (!$.isEmptyObject(column.grouping)) {
var groupableIcon = $("<span class='slick-column-groupable' />");
if(options.groupIconCssClass) groupableIcon.addClass(options.groupIconCssClass)
if(options.groupIconImage) groupableIcon.css("background", "url(" + options.groupIconImage + ") no-repeat center center");
$(node).css('cursor', 'pointer').append(groupableIcon);
}
})
for (var i = 0; i < _gridColumns.length; i++) {
var columnId = _gridColumns[i].field;
_grid.updateColumnHeader(columnId);
}
}
function setupColumnReorder(grid, $headers, headerColumnWidthDiff, setColumns, setupColumnResize, columns, getColumnIndex, uid, trigger) {
$headers.filter(":ui-sortable").sortable("destroy");
var $headerDraggableGroupBy = $(grid.getPreHeaderPanel());
$headers.sortable({
distance: 3,
cursor: "default",
tolerance: "intersection",
helper: "clone",
placeholder: "slick-sortable-placeholder ui-state-default slick-header-column",
forcePlaceholderSize: true,
appendTo: "body",
start: function(e, ui) {
$(ui.helper).addClass("slick-header-column-active");
$headerDraggableGroupBy.find(".slick-placeholder").show();
$headerDraggableGroupBy.find(".slick-dropped-grouping").hide();
},
beforeStop: function(e, ui) {
$(ui.helper).removeClass("slick-header-column-active");
var hasDroppedColumn = $headerDraggableGroupBy.find(".slick-dropped-grouping").length;
if(hasDroppedColumn > 0){
$headerDraggableGroupBy.find(".slick-placeholder").hide();
$headerDraggableGroupBy.find(".slick-dropped-grouping").show();
}
},
stop: function(e) {
if (!grid.getEditorLock().commitCurrentEdit()) {
$(this).sortable("cancel");
return;
}
var reorderedIds = $headers.sortable("toArray");
var reorderedColumns = [];
for (var i = 0; i < reorderedIds.length; i++) {
reorderedColumns.push(columns[getColumnIndex(reorderedIds[i].replace(uid, ""))]);
}
setColumns(reorderedColumns);
trigger(grid.onColumnsReordered, {
grid: grid
});
e.stopPropagation();
setupColumnResize();
}
});
}
/**

@@ -61,2 +148,3 @@ * Destroy plugin.

function destroy() {
onGroupChanged.unsubscribe();
}

@@ -112,6 +200,18 @@

columnsGroupBy = newGroupingOrder;
updateGroupBy();
updateGroupBy("sort-group");
}
});
emptyDropbox = dropbox.html();
groupToggler.on('click', function(e) {
if (this.classList.contains('collapsed')) {
this.classList.remove('collapsed');
this.classList.add('expanded');
_dataView.expandAllGroups();
} else {
this.classList.add('collapsed');
this.classList.remove('expanded');
_dataView.collapseAllGroups();
}
});
}

@@ -133,6 +233,12 @@

if (e.id == columnid) {
if (e.grouping != null) {
if (e.grouping != null && !$.isEmptyObject(e.grouping)) {
var entry = $("<div id='" + _gridUid + e.id + "_entry' data-id='" + e.id + "' class='slick-dropped-grouping'>");
var span = $("<span class='slick-groupby-remove'></span>").text(column.text() + " ")
span.appendTo(entry);
var groupText = $("<div style='display: inline-flex'>" + column.text() + "</div>")
groupText.appendTo(entry);
var groupRemoveIcon = $("<div class='slick-groupby-remove'>&nbsp;</div>")
if(options.deleteIconCssClass) groupRemoveIcon.addClass(options.deleteIconCssClass);
if(options.deleteIconImage) groupRemoveIcon.css("background", "url(" + options.deleteIconImage + ") no-repeat center right");
if(!options.deleteIconCssClass && !options.deleteIconImage) groupRemoveIcon.addClass('slick-groupby-remove-image');
groupRemoveIcon.appendTo(entry);
$("</div>").appendTo(entry);

@@ -145,2 +251,3 @@ entry.appendTo(container);

});
groupToggler.css('display', 'block');
}

@@ -151,3 +258,3 @@ }

columnsGroupBy.push(column);
updateGroupBy();
updateGroupBy("add-group");
}

@@ -157,3 +264,3 @@

var text = entry;
$("#" + _gridUid + id + "_entry").on('click', function() {
$("#" + _gridUid + id + "_entry >.slick-groupby-remove").on('click', function() {
$(this).off('click');

@@ -164,4 +271,16 @@ removeGroupBy(id, column, text);

function setDroppedGroups(groupingInfo) {
groupingInfos = (groupingInfo instanceof Array) ? groupingInfo : [groupingInfo];
dropboxPlaceholder.hide()
for (var i = 0; i < groupingInfos.length; i++) {
var column = $(_grid.getHeaderColumn(groupingInfos[i]));
handleGroupByDrop(dropbox, column);
}
}
function clearDroppedGroups() {
columnsGroupBy = [];
updateGroupBy("clear-all");
dropbox.find(".slick-dropped-grouping").remove();
groupToggler.css("display", "none");
dropboxPlaceholder.show()
}

@@ -192,8 +311,9 @@

}
updateGroupBy();
updateGroupBy("remove-group");
}
function updateGroupBy() {
function updateGroupBy(originator) {
if (columnsGroupBy.length == 0) {
_dataView.setGrouping([]);
onGroupChanged.notify({ caller: originator, groupColumns: [] });
return;

@@ -209,2 +329,3 @@ }

*/
onGroupChanged.notify({ caller: originator, groupColumns: groupingArray})
}

@@ -216,5 +337,8 @@

"destroy": destroy,
"clearDroppedGroups": clearDroppedGroups
"onGroupChanged": onGroupChanged,
"setDroppedGroups": setDroppedGroups,
"clearDroppedGroups": clearDroppedGroups,
"getSetupColumnReorder": setupColumnReorder,
});
}
})(jQuery);
})(jQuery);

@@ -6,17 +6,21 @@ /***

* http://violet313.org/slickgrids/#intro
*
*
* USAGE:
*
* Add the slick.rowDetailView.(js|css) files and register the plugin with the grid.
*
* AVAILABLE ROW DETAIL OPTIONS:
* cssClass: A CSS class to be added to the row detail
* loadOnce: Booleang flag, when True will load the data once and then reuse it.
* preTemplate: Template that will be used before the async process (typically used to show a spinner/loading)
* postTemplate: Template that will be loaded once the async function finishes
* process: Async server function call
* panelRows: Row count to use for the template panel
* useRowClick: Boolean flag, when True will open the row detail on a row click (from any column), default to False
*
* cssClass: A CSS class to be added to the row detail
* expandedClass: Extra classes to be added to the expanded Toggle
* collapsedClass: Extra classes to be added to the collapse Toggle
* loadOnce: Defaults to false, when set to True it will load the data once and then reuse it.
* preTemplate: Template that will be used before the async process (typically used to show a spinner/loading)
* postTemplate: Template that will be loaded once the async function finishes
* process: Async server function call
* panelRows: Row count to use for the template panel
* useRowClick: Boolean flag, when True will open the row detail on a row click (from any column), default to False
* keyPrefix: Defaults to '_', prefix used for all the plugin metadata added to the item object (meta e.g.: padding, collapsed, parent)
* collapseAllOnSort: Defaults to true, which will collapse all row detail views when user calls a sort. Unless user implements a sort to deal with padding
* saveDetailViewOnScroll: Defaults to true, which will save the row detail view in a cache when it detects that it will become out of the viewport buffer
* useSimpleViewportCalc: Defaults to false, which will use simplified calculation of out or back of viewport visibility
*
* AVAILABLE PUBLIC OPTIONS:

@@ -26,27 +30,51 @@ * init: initiliaze the plugin

* collapseAll: collapse all opened row detail panel
* getColumnDefinition: get the column definitions
* collapseDetailView: collapse a row by passing the item object (row detail)
* expandDetailView: expand a row by passing the item object (row detail)
* getColumnDefinition: get the column definitions
* getExpandedRows: get all the expanded rows
* getFilterItem: takes in the item we are filtering and if it is an expanded row returns it's parents row to filter on
* getOptions: get current plugin options
* resizeDetailView: resize a row detail view, it will auto-calculate the number of rows it needs
* saveDetailView: save a row detail view content by passing the row object
* setOptions: set or change some of the plugin options
*
*
* THE PLUGIN EXPOSES THE FOLLOWING SLICK EVENTS:
* onAsyncResponse: This event must be used with the "notify" by the end user once the Asynchronous Server call returns the item detail
* Event args:
* itemDetail: Item detail returned from the async server call
* detailView: An explicit view to use instead of template (Optional)
* onAsyncResponse: This event must be used with the "notify" by the end user once the Asynchronous Server call returns the item detail
* Event args:
* item: Item detail returned from the async server call
* detailView: An explicit view to use instead of template (Optional)
*
* onAsyncEndUpdate: Fired when the async response finished
* Event args:
* grid: Reference to the grid.
* itemDetail: Column definition.
*
* Event args:
* grid: Reference to the grid.
* item: Item data context
*
* onBeforeRowDetailToggle: Fired before the row detail gets toggled
* Event args:
* grid: Reference to the grid.
* item: Column definition.
*
* Event args:
* grid: Reference to the grid.
* item: Item data context
*
* onAfterRowDetailToggle: Fired after the row detail gets toggled
* Event args:
* grid: Reference to the grid.
* item: Column definition.
* Event args:
* grid: Reference to the grid.
* item: Item data context
* expandedRows: Array of the Expanded Rows
*
* onRowOutOfViewportRange: Fired after a row becomes out of viewport range (user can't see the row anymore)
* Event args:
* grid: Reference to the grid.
* item: Item data context
* rowId: Id of the Row object (datacontext) in the Grid
* rowIndex: Index of the Row in the Grid
* expandedRows: Array of the Expanded Rows
* rowIdsOutOfViewport: Array of the Out of viewport Range Rows
*
* onRowBackToViewportRange: Fired after the row detail gets toggled
* Event args:
* grid: Reference to the grid.
* item: Item data context
* rowId: Id of the Row object (datacontext) in the Grid
* rowIndex: Index of the Row in the Grid
* expandedRows: Array of the Expanded Rows
* rowIdsOutOfViewport: Array of the Out of viewport Range Rows
*/

@@ -63,22 +91,48 @@ (function ($) {

/** Constructor of the Row Detail View Plugin */
function RowDetailView(options) {
var _grid;
var _gridOptions;
var _gridUid;
var _self = this;
var _lastRange = null;
var _expandedRows = [];
var _handler = new Slick.EventHandler();
var _outsideRange = 5;
var _visibleRenderedCellCount = 0;
var _defaults = {
columnId: "_detail_selector",
cssClass: null,
toolTip: "",
width: 30
columnId: '_detail_selector',
cssClass: 'detailView-toggle',
expandedClass: null,
collapsedClass: null,
keyPrefix: '_',
loadOnce: false,
collapseAllOnSort: true,
saveDetailViewOnScroll: true,
useSimpleViewportCalc: false,
toolTip: '',
width: 30,
maxRows: null
};
var _keyPrefix = _defaults.keyPrefix;
var _gridRowBuffer = 0;
var _rowIdsOutOfViewport = [];
var _options = $.extend(true, {}, _defaults, options);
/**
* Initialize the plugin, which requires user to pass the SlickGrid Grid object
* @param grid: SlickGrid Grid object
*/
function init(grid) {
if (!grid) {
throw new Error('RowDetailView Plugin requires the Grid instance to be passed as argument to the "init()" method');
}
_grid = grid;
_gridUid = grid.getUID();
_gridOptions = grid.getOptions() || {};
_dataView = _grid.getData();
_keyPrefix = _options && _options.keyPrefix || '_';
// Update the minRowBuffer so that the view doesn't disappear when it's at top of screen + the original default 3
_gridRowBuffer = _grid.getOptions().minRowBuffer;
_grid.getOptions().minRowBuffer = _options.panelRows + 3;

@@ -88,12 +142,37 @@

.subscribe(_grid.onClick, handleClick)
.subscribe(_grid.onSort, handleSort)
.subscribe(_grid.onScroll, handleScroll);
.subscribe(_grid.onScroll, handleScroll);
_grid.getData().onRowCountChanged.subscribe(function () { _grid.updateRowCount(); _grid.render(); });
_grid.getData().onRowsChanged.subscribe(function (e, a) { _grid.invalidateRows(a.rows); _grid.render(); });
// Sort will, by default, Collapse all of the open items (unless user implements his own onSort which deals with open row and padding)
if (_options.collapseAllOnSort) {
_handler.subscribe(_grid.onSort, collapseAll);
_expandedRows = [];
_rowIdsOutOfViewport = [];
}
_handler.subscribe(_grid.getData().onRowCountChanged, function () {
_grid.updateRowCount();
_grid.render();
});
_handler.subscribe(_grid.getData().onRowsChanged, function (e, a) {
_grid.invalidateRows(a.rows);
_grid.render();
});
// subscribe to the onAsyncResponse so that the plugin knows when the user server side calls finished
subscribeToOnAsyncResponse();
// if we use the alternative & simpler calculation of the out of viewport range
// we will need to know how many rows are rendered on the screen and we need to wait for grid to be rendered
// unfortunately there is no triggered event for knowing when grid is finished, so we use 250ms delay and it's typically more than enough
if (_options.useSimpleViewportCalc) {
_handler.subscribe(_grid.onRendered, function(e, args) {
if (args && args.endRow) {
_visibleRenderedCellCount = args.endRow - args.startRow;
}
});
}
}
/** destroy the plugin and it's events */
function destroy() {

@@ -105,15 +184,32 @@ _handler.unsubscribeAll();

_self.onBeforeRowDetailToggle.unsubscribe();
_self.onRowOutOfViewportRange.unsubscribe();
_self.onRowBackToViewportRange.unsubscribe();
}
function getOptions(options) {
/** Get current plugin options */
function getOptions() {
return _options;
}
/** set or change some of the plugin options */
function setOptions(options) {
_options = $.extend(true, {}, _options, options);
}
/** Find a value in an array and return the index when (or -1 when not found) */
function arrayFindIndex(sourceArray, value) {
if (sourceArray) {
for (var i = 0; i < sourceArray.length; i++) {
if (sourceArray[i] === value) {
return i;
}
}
}
return -1;
}
/** Handle mouse click event */
function handleClick(e, args) {
// clicking on a row select checkbox
if (_options.useRowClick || _grid.getColumns()[args.cell].id === _options.columnId && $(e.target).hasClass("detailView-toggle")) {
if (_options.useRowClick || _grid.getColumns()[args.cell].id === _options.columnId && $(e.target).hasClass(_options.cssClass)) {
// if editing, try to commit

@@ -130,4 +226,4 @@ if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {

_self.onBeforeRowDetailToggle.notify({
"grid": _grid,
"item": item
'grid': _grid,
'item': item
}, e, _self);

@@ -139,4 +235,5 @@

_self.onAfterRowDetailToggle.notify({
"grid": _grid,
"item": item
'grid': _grid,
'item': item,
'expandedRows': _expandedRows,
}, e, _self);

@@ -149,86 +246,193 @@

// Sort will just collapse all of the open items
function handleSort(e, args) {
collapseAll();
/** If we scroll save detail views that go out of cache range */
function handleScroll(e, args) {
if (_options.useSimpleViewportCalc) {
calculateOutOfRangeViewsSimplerVersion();
} else {
calculateOutOfRangeViews();
}
}
// If we scroll save detail views that go out of cache range
function handleScroll(e, args) {
var range = _grid.getRenderedRange();
/** Calculate when expanded rows become out of view range */
function calculateOutOfRangeViews() {
if (_grid) {
var renderedRange = _grid.getRenderedRange();
// Only check if we have expanded rows
if (_expandedRows.length > 0) {
// Assume scroll direction is down by default.
var scrollDir = 'DOWN';
if (_lastRange) {
// Some scrolling isn't anything as the range is the same
if (_lastRange.top === renderedRange.top && _lastRange.bottom === renderedRange.bottom) {
return;
}
var start = (range.top > 0 ? range.top : 0);
var end = (range.bottom > _dataView.getLength() ? range.bottom : _dataView.getLength());
// Get the item at the top of the view
var topMostItem = _dataView.getItemByIdx(start);
// Check it is a parent item
if (topMostItem._parent == undefined)
{
// This is a standard row as we have no parent.
var nextItem = _dataView.getItemByIdx(start + 1);
if(nextItem !== undefined && nextItem._parent !== undefined)
{
// This is likely the expanded Detail Row View
// Check for safety
if(nextItem._parent == topMostItem)
{
saveDetailView(topMostItem);
}
// If our new top is smaller we are scrolling up
if (_lastRange.top > renderedRange.top ||
// Or we are at very top but our bottom is increasing
(_lastRange.top === 0 && renderedRange.top === 0) && _lastRange.bottom > renderedRange.bottom) {
scrollDir = 'UP';
}
}
}
// Find the bottom most item that is likely to go off screen
var bottomMostItem = _dataView.getItemByIdx(end - 1);
_expandedRows.forEach(function (row) {
var rowIndex = _dataView.getRowById(row.id);
// If we are a detailView and we are about to go out of cache view
if(bottomMostItem._parent !== undefined)
{
saveDetailView(bottomMostItem._parent);
var rowPadding = row[_keyPrefix + 'sizePadding'];
var rowOutOfRange = arrayFindIndex(_rowIdsOutOfViewport, row.id) >= 0;
if (scrollDir === 'UP') {
// save the view when asked
if (_options.saveDetailViewOnScroll) {
// If the bottom item within buffer range is an expanded row save it.
if (rowIndex >= renderedRange.bottom - _gridRowBuffer) {
saveDetailView(row);
}
}
// If the row expanded area is within the buffer notify that it is back in range
if (rowOutOfRange && rowIndex - _outsideRange < renderedRange.top && rowIndex >= renderedRange.top) {
notifyBackToViewportWhenDomExist(row, row.id);
}
// if our first expanded row is about to go off the bottom
else if (!rowOutOfRange && (rowIndex + rowPadding) > renderedRange.bottom) {
notifyOutOfViewport(row, row.id);
}
}
else if (scrollDir === 'DOWN') {
// save the view when asked
if (_options.saveDetailViewOnScroll) {
// If the top item within buffer range is an expanded row save it.
if (rowIndex <= renderedRange.top + _gridRowBuffer) {
saveDetailView(row);
}
}
// If row index is i higher than bottom with some added value (To ignore top rows off view) and is with view and was our of range
if (rowOutOfRange && (rowIndex + rowPadding + _outsideRange) > renderedRange.bottom && rowIndex < rowIndex + rowPadding) {
notifyBackToViewportWhenDomExist(row, row.id);
}
// if our row is outside top of and the buffering zone but not in the array of outOfVisable range notify it
else if (!rowOutOfRange && rowIndex < renderedRange.top) {
notifyOutOfViewport(row, row.id);
}
}
});
_lastRange = renderedRange;
}
}
/** This is an alternative & more simpler version of the Calculate when expanded rows become out of view range */
function calculateOutOfRangeViewsSimplerVersion() {
if (_grid) {
var renderedRange = _grid.getRenderedRange();
_expandedRows.forEach(function (row) {
var rowIndex = _dataView.getRowById(row.id);
var isOutOfVisibility = checkIsRowOutOfViewportRange(rowIndex, renderedRange);
if (!isOutOfVisibility && arrayFindIndex(_rowIdsOutOfViewport, row.id) >= 0) {
notifyBackToViewportWhenDomExist(row, row.id);
} else if (isOutOfVisibility) {
notifyOutOfViewport(row, row.id);
}
});
}
}
/**
* Check if the row became out of visible range (when user can't see it anymore)
* @param rowIndex
* @param renderedRange from SlickGrid
*/
function checkIsRowOutOfViewportRange(rowIndex, renderedRange) {
if (Math.abs(renderedRange.bottom - _gridRowBuffer - rowIndex) > _visibleRenderedCellCount * 2) {
return true;
}
return false;
}
/** Send a notification, through "onRowOutOfViewportRange", that is out of the viewport range */
function notifyOutOfViewport(item, rowId) {
var rowIndex = item.rowIndex || _dataView.getRowById(item.id);
_self.onRowOutOfViewportRange.notify({
'grid': _grid,
'item': item,
'rowId': rowId,
'rowIndex': rowIndex,
'expandedRows': _expandedRows,
'rowIdsOutOfViewport': syncOutOfViewportArray(rowId, true)
}, null, _self);
}
/** Send a notification, through "onRowBackToViewportRange", that a row came back to the viewport */
function notifyBackToViewportWhenDomExist(item, rowId) {
var rowIndex = item.rowIndex || _dataView.getRowById(item.id);
setTimeout(function() {
// make sure View Row DOM Element really exist before notifying that it's a row that is visible again
if ($('.cellDetailView_' + item.id).length) {
_self.onRowBackToViewportRange.notify({
'grid': _grid,
'item': item,
'rowId': rowId,
'rowIndex': rowIndex,
'expandedRows': _expandedRows,
'rowIdsOutOfViewport': syncOutOfViewportArray(rowId, false)
}, null, _self);
}
}, 100);
}
/**
* This function will sync the out of viewport array whenever necessary.
* The sync can add a row (when necessary, no need to add again if it already exist) or delete a row from the array.
* @param rowId: number
* @param isAdding: are we adding or removing a row?
*/
function syncOutOfViewportArray(rowId, isAdding) {
var arrayRowIndex = arrayFindIndex(_rowIdsOutOfViewport, rowId);
if (isAdding && arrayRowIndex < 0) {
_rowIdsOutOfViewport.push(rowId);
} else if (!isAdding && arrayRowIndex >= 0) {
_rowIdsOutOfViewport.splice(arrayRowIndex, 1);
}
return _rowIdsOutOfViewport;
}
// Toggle between showing and hiding a row
function toggleRowSelection(row) {
_grid.getData().beginUpdate();
HandleAccordionShowHide(row);
_grid.getData().endUpdate();
_dataView.beginUpdate();
handleAccordionShowHide(row);
_dataView.endUpdate();
}
// Collapse all of the open items
/** Collapse all of the open items */
function collapseAll() {
_dataView.beginUpdate();
for (var i = _expandedRows.length - 1; i >= 0; i--) {
collapseItem(_expandedRows[i]);
collapseDetailView(_expandedRows[i], true);
}
_dataView.endUpdate();
}
// Saves the current state of the detail view
function saveDetailView(item)
{
var view = $("#innerDetailView_" + item.id);
if (view)
{
var html = $("#innerDetailView_" + item.id).html();
if(html !== undefined)
{
item._detailContent = html;
}
}
}
// Colapse an Item so it is notlonger seen
function collapseItem(item) {
/** Colapse an Item so it is not longer seen */
function collapseDetailView(item, isMultipleCollapsing) {
if (!isMultipleCollapsing) {
_dataView.beginUpdate();
}
// Save the details on the collapse assuming onetime loading
if (_options.loadOnce) {
saveDetailView(item);
saveDetailView(item);
}
item._collapsed = true;
for (var idx = 1; idx <= item._sizePadding; idx++) {
_dataView.deleteItem(item.id + "." + idx);
item[_keyPrefix + 'collapsed'] = true;
for (var idx = 1; idx <= item[_keyPrefix + 'sizePadding']; idx++) {
_dataView.deleteItem(item.id + '.' + idx);
}
item._sizePadding = 0;
item[_keyPrefix + 'sizePadding'] = 0;
_dataView.updateItem(item.id, item);

@@ -240,19 +444,24 @@

});
if (!isMultipleCollapsing) {
_dataView.endUpdate();
}
}
// Expand a row given the dataview item that is to be expanded
function expandItem(item) {
item._collapsed = false;
/** Expand a row given the dataview item that is to be expanded */
function expandDetailView(item) {
item[_keyPrefix + 'collapsed'] = false;
_expandedRows.push(item);
// In the case something went wrong loading it the first time such a scroll of screen before loaded
if (!item._detailContent) item._detailViewLoaded = false;
if (!item[_keyPrefix + 'detailContent']) item[_keyPrefix + 'detailViewLoaded'] = false;
// display pre-loading template
if (!item._detailViewLoaded || _options.loadOnce !== true) {
item._detailContent = _options.preTemplate(item);
if (!item[_keyPrefix + 'detailViewLoaded'] || _options.loadOnce !== true) {
item[_keyPrefix + 'detailContent'] = _options.preTemplate(item);
} else {
_self.onAsyncResponse.notify({
"itemDetail": item,
"detailView": item._detailContent
'item': item,
'itemDetail': item,
'detailView': item[_keyPrefix + 'detailContent']
}, undefined, this);

@@ -272,28 +481,41 @@ applyTemplateNewLineHeight(item);

/** Saves the current state of the detail view */
function saveDetailView(item) {
var view = $('.' + _gridUid + ' .innerDetailView_' + item.id);
if (view) {
var html = $('.' + _gridUid + ' .innerDetailView_' + item.id).html();
if (html !== undefined) {
item[_keyPrefix + 'detailContent'] = html;
}
}
}
/**
* subscribe to the onAsyncResponse so that the plugin knows when the user server side calls finished
* the response has to be as "args.itemDetail" with it's data back
* the response has to be as "args.item" (or "args.itemDetail") with it's data back
*/
function subscribeToOnAsyncResponse() {
_self.onAsyncResponse.subscribe(function (e, args) {
if (!args || !args.itemDetail) {
throw 'Slick.RowDetailView plugin requires the onAsyncResponse() to supply "args.itemDetail" property.'
function subscribeToOnAsyncResponse() {
_self.onAsyncResponse.subscribe(function (e, args) {
if (!args || (!args.item && !args.itemDetail)) {
throw 'Slick.RowDetailView plugin requires the onAsyncResponse() to supply "args.item" property.'
}
// we accept item/itemDetail, just get the one which has data
var itemDetail = args.item || args.itemDetail;
// If we just want to load in a view directly we can use detailView property to do so
if (args.detailView) {
args.itemDetail._detailContent = args.detailView;
itemDetail[_keyPrefix + 'detailContent'] = args.detailView;
} else {
args.itemDetail._detailContent = _options.postTemplate(args.itemDetail);
itemDetail[_keyPrefix + 'detailContent'] = _options.postTemplate(itemDetail);
}
args.itemDetail._detailViewLoaded = true;
itemDetail[_keyPrefix + 'detailViewLoaded'] = true;
_dataView.updateItem(itemDetail.id, itemDetail);
var idxParent = _dataView.getIdxById(args.itemDetail.id);
_dataView.updateItem(args.itemDetail.id, args.itemDetail);
// trigger an event once the post template is finished loading
_self.onAsyncEndUpdate.notify({
"grid": _grid,
"itemDetail": args.itemDetail
'grid': _grid,
'item': itemDetail,
'itemDetail': itemDetail
}, e, _self);

@@ -303,8 +525,9 @@ });

function HandleAccordionShowHide(item) {
/** When row is getting toggled, we will handle the action of collapsing/expanding */
function handleAccordionShowHide(item) {
if (item) {
if (!item._collapsed) {
collapseItem(item);
if (!item[_keyPrefix + 'collapsed']) {
collapseDetailView(item);
} else {
expandItem(item);
expandDetailView(item);
}

@@ -316,2 +539,4 @@ }

//////////////////////////////////////////////////////////////
/** Get the Row Detail padding (which are the rows dedicated to the detail panel) */
var getPaddingItem = function (parent, offset) {

@@ -323,9 +548,9 @@ var item = {};

}
item.id = parent.id + "." + offset;
item.id = parent.id + '.' + offset;
//additional hidden padding metadata fields
item._collapsed = true;
item._isPadding = true;
item._parent = parent;
item._offset = offset;
// additional hidden padding metadata fields
item[_keyPrefix + 'collapsed'] = true;
item[_keyPrefix + 'isPadding'] = true;
item[_keyPrefix + 'parent'] = parent;
item[_keyPrefix + 'offset'] = offset;

@@ -336,16 +561,15 @@ return item;

//////////////////////////////////////////////////////////////
//create the detail ctr node. this belongs to the dev & can be custom-styled as per
// create the detail ctr node. this belongs to the dev & can be custom-styled as per
//////////////////////////////////////////////////////////////
function applyTemplateNewLineHeight(item) {
// the height seems to be calculated by the template row count (how many line of items does the template have)
// the height is calculated by the template row count (how many line of items does the template view have)
var rowCount = _options.panelRows;
//calculate padding requirements based on detail-content..
//ie. worst-case: create an invisible dom node now &find it's height.
var lineHeight = 13; //we know cuz we wrote the custom css innit ;)
item._sizePadding = Math.ceil(((rowCount * 2) * lineHeight) / _grid.getOptions().rowHeight);
item._height = (item._sizePadding * _grid.getOptions().rowHeight);
// calculate padding requirements based on detail-content..
// ie. worst-case: create an invisible dom node now & find it's height.
var lineHeight = 13; // we know cuz we wrote the custom css init ;)
item[_keyPrefix + 'sizePadding'] = Math.ceil(((rowCount * 2) * lineHeight) / _gridOptions.rowHeight);
item[_keyPrefix + 'height'] = (item[_keyPrefix + 'sizePadding'] * _gridOptions.rowHeight);
var idxParent = _dataView.getIdxById(item.id);
for (var idx = 1; idx <= item._sizePadding; idx++) {
for (var idx = 1; idx <= item[_keyPrefix + 'sizePadding']; idx++) {
_dataView.insertItem(idxParent + idx, getPaddingItem(item, idx));

@@ -355,9 +579,9 @@ }

/** Get the Column Definition of the first column dedicated to toggling the Row Detail View */
function getColumnDefinition() {
return {
id: _options.columnId,
name: "",
name: '',
toolTip: _options.toolTip,
field: "sel",
field: 'sel',
width: _options.width,

@@ -371,22 +595,38 @@ resizable: false,

/** return the currently expanded rows */
function getExpandedRows() {
return _expandedRows;
}
/** The Formatter of the toggling icon of the Row Detail */
function detailSelectionFormatter(row, cell, value, columnDef, dataContext) {
if (dataContext[_keyPrefix + 'collapsed'] == undefined) {
dataContext[_keyPrefix + 'collapsed'] = true,
dataContext[_keyPrefix + 'sizePadding'] = 0, //the required number of pading rows
dataContext[_keyPrefix + 'height'] = 0, //the actual height in pixels of the detail field
dataContext[_keyPrefix + 'isPadding'] = false,
dataContext[_keyPrefix + 'parent'] = undefined,
dataContext[_keyPrefix + 'offset'] = 0
}
if (dataContext._collapsed == undefined) {
dataContext._collapsed = true,
dataContext._sizePadding = 0, //the required number of pading rows
dataContext._height = 0, //the actual height in pixels of the detail field
dataContext._isPadding = false,
dataContext._parent = undefined,
dataContext._offset = 0
if (dataContext[_keyPrefix + 'isPadding'] == true) {
// render nothing
}
if (dataContext._isPadding == true) {
//render nothing
} else if (dataContext._collapsed) {
return "<div class='detailView-toggle expand'></div>";
} else {
else if (dataContext[_keyPrefix + 'collapsed']) {
var collapsedClasses = _options.cssClass + ' expand ';
if (_options.collapsedClass) {
collapsedClasses += _options.collapsedClass;
}
return '<div class="' + collapsedClasses + '"></div>';
}
else {
var html = [];
var rowHeight = _grid.getOptions().rowHeight;
var bottomMargin = 5;
var rowHeight = _gridOptions.rowHeight;
var outterHeight = dataContext[_keyPrefix + 'sizePadding'] * _gridOptions.rowHeight;
if (_options.maxRows !== null && dataContext[_keyPrefix + 'sizePadding'] > _options.maxRows) {
outterHeight = _options.maxRows * rowHeight;
dataContext[_keyPrefix + 'sizePadding'] = _options.maxRows;
}
//V313HAX:

@@ -401,12 +641,14 @@ //putting in an extra closing div after the closing toggle div and ommiting a

//sneaky extra </div> inserted here-----------------v
html.push("<div class='detailView-toggle collapse'></div></div>");
var expandedClasses = _options.cssClass + ' collapse ';
if (_options.expandedClass) expandedClasses += _options.expandedClass;
html.push('<div class="' + expandedClasses + '"></div></div>');
html.push("<div id='cellDetailView_", dataContext.id, "' class='dynamic-cell-detail' "); //apply custom css to detail
html.push("style='height:", dataContext._height, "px;"); //set total height of padding
html.push("top:", rowHeight, "px'>"); //shift detail below 1st row
html.push("<div id='detailViewContainer_", dataContext.id, "' class='detail-container' style='max-height:" + (dataContext._height - rowHeight + bottomMargin) + "px'>"); //sub ctr for custom styling
html.push("<div id='innerDetailView_" , dataContext.id , "'>" , dataContext._detailContent, "</div></div>");
//&omit a final closing detail container </div> that would come next
html.push('<div class="dynamic-cell-detail cellDetailView_', dataContext.id, '" '); //apply custom css to detail
html.push('style="height:', outterHeight, 'px;'); //set total height of padding
html.push('top:', rowHeight, 'px">'); //shift detail below 1st row
html.push('<div class="detail-container detailViewContainer_', dataContext.id, '" style="min-height:' + dataContext[_keyPrefix + 'height'] + 'px">'); //sub ctr for custom styling
html.push('<div class="innerDetailView_', dataContext.id, '">', dataContext[_keyPrefix + 'detailContent'], '</div></div>');
// &omit a final closing detail container </div> that would come next
return html.join("");
return html.join('');
}

@@ -416,44 +658,68 @@ return null;

/** Resize the Row Detail View */
function resizeDetailView(item) {
if (!item) return;
// Grad each of the dom items
var mainContainer = document.getElementById('detailViewContainer_' + item.id);
var cellItem = document.getElementById('cellDetailView_' + item.id);
var inner = document.getElementById('innerDetailView_' + item.id);
if (!mainContainer || !cellItem || !inner) return;
for (var idx = 1; idx <= item._sizePadding; idx++) {
_dataView.deleteItem(item.id + "." + idx);
if (!item) {
return;
}
var rowHeight = _grid.getOptions().rowHeight; // height of a row
var lineHeight = 13; //we know cuz we wrote the custom css innit ;)
// Get the inner Item height as this will be the actual size
var itemHeight = inner.clientHeight;
// Now work out how many rows
var rowCount = Math.ceil(itemHeight / rowHeight) + 1;
item._sizePadding = Math.ceil(((rowCount * 2) * lineHeight) / rowHeight);
item._height = (item._sizePadding * rowHeight);
// If the padding is now more than the original minRowBuff we need to increase it
if (_grid.getOptions().minRowBuffer < item._sizePadding)
{
// Update the minRowBuffer so that the view doesn't disappear when it's at top of screen + the original default 3
_grid.getOptions().minRowBuffer =item._sizePadding + 3;
// Grad each of the DOM elements
var mainContainer = document.querySelector('.' + _gridUid + ' .detailViewContainer_' + item.id);
var cellItem = document.querySelector('.' + _gridUid + ' .cellDetailView_' + item.id);
var inner = document.querySelector('.' + _gridUid + ' .innerDetailView_' + item.id);
if (!mainContainer || !cellItem || !inner) {
return;
}
mainContainer.setAttribute("style", "max-height: " + item._height + "px");
if (cellItem) cellItem.setAttribute("style", "height: " + item._height + "px;top:" + rowHeight + "px");
for (var idx = 1; idx <= item[_keyPrefix + 'sizePadding']; idx++) {
_dataView.deleteItem(item.id + '.' + idx);
}
var rowHeight = _gridOptions.rowHeight; // height of a row
var lineHeight = 13; // we know cuz we wrote the custom css innit ;)
// remove the height so we can calculate the height
mainContainer.style.minHeight = null;
// Get the scroll height for the main container so we know the actual size of the view
var itemHeight = mainContainer.scrollHeight;
// Now work out how many rows
var rowCount = Math.ceil(itemHeight / rowHeight);
item[_keyPrefix + 'sizePadding'] = Math.ceil(((rowCount * 2) * lineHeight) / rowHeight);
item[_keyPrefix + 'height'] = itemHeight;
var outterHeight = (item[_keyPrefix + 'sizePadding'] * rowHeight);
if (_options.maxRows !== null && item[_keyPrefix + 'sizePadding'] > _options.maxRows) {
outterHeight = _options.maxRows * rowHeight;
item[_keyPrefix + 'sizePadding'] = _options.maxRows;
}
// If the padding is now more than the original minRowBuff we need to increase it
if (_grid.getOptions().minRowBuffer < item[_keyPrefix + 'sizePadding']) {
// Update the minRowBuffer so that the view doesn't disappear when it's at top of screen + the original default 3
_grid.getOptions().minRowBuffer = item[_keyPrefix + 'sizePadding'] + 3;
}
mainContainer.setAttribute('style', 'min-height: ' + item[_keyPrefix + 'height'] + 'px');
if (cellItem) cellItem.setAttribute('style', 'height: ' + outterHeight + 'px; top:' + rowHeight + 'px');
var idxParent = _dataView.getIdxById(item.id);
for (var idx = 1; idx <= item._sizePadding; idx++) {
_dataView.insertItem(idxParent + idx, getPaddingItem(item, idx));
for (var idx = 1; idx <= item[_keyPrefix + 'sizePadding']; idx++) {
_dataView.insertItem(idxParent + idx, getPaddingItem(item, idx));
}
// Lastly save the updated state
saveDetailView(item);
}
/** Takes in the item we are filtering and if it is an expanded row returns it's parents row to filter on */
function getFilterItem(item) {
if (item[_keyPrefix + 'isPadding'] && item[_keyPrefix + 'parent']) {
item = item[_keyPrefix + 'parent'];
}
return item;
}
$.extend(this, {

@@ -463,5 +729,13 @@ "init": init,

"collapseAll": collapseAll,
"collapseDetailView": collapseDetailView,
"expandDetailView": expandDetailView,
"getColumnDefinition": getColumnDefinition,
"getExpandedRows": getExpandedRows,
"getFilterItem": getFilterItem,
"getOptions": getOptions,
"resizeDetailView": resizeDetailView,
"saveDetailView": saveDetailView,
"setOptions": setOptions,
// events
"onAsyncResponse": new Slick.Event(),

@@ -471,5 +745,6 @@ "onAsyncEndUpdate": new Slick.Event(),

"onBeforeRowDetailToggle": new Slick.Event(),
"resizeDetailView": resizeDetailView
"onRowOutOfViewportRange": new Slick.Event(),
"onRowBackToViewportRange": new Slick.Event()
});
}
})(jQuery);
## This is the 6pac SlickGrid repo
Check out the NEW SlickGrid Website! http://slickgrid.net/
This is the acknowledged most active non-customised fork of SlickGrid.

@@ -9,2 +11,2 @@

Also check out the [wiki](https://github.com/6pac/SlickGrid/wiki) for news and documentation.
Also check out the [wiki](https://github.com/6pac/SlickGrid/wiki) for news and documentation.

@@ -27,4 +27,6 @@ /***

"GlobalEditorLock": new EditorLock(),
"TreeColumns": TreeColumns,
"keyCode": {
SPACE: 8,
BACKSPACE: 8,

@@ -492,4 +494,176 @@ DELETE: 46,

}
/**
*
* @param {Array} treeColumns Array com levels of columns
* @returns {{hasDepth: 'hasDepth', getTreeColumns: 'getTreeColumns', extractColumns: 'extractColumns', getDepth: 'getDepth', getColumnsInDepth: 'getColumnsInDepth', getColumnsInGroup: 'getColumnsInGroup', visibleColumns: 'visibleColumns', filter: 'filter', reOrder: reOrder}}
* @constructor
*/
function TreeColumns(treeColumns) {
var columnsById = {};
function init() {
mapToId(treeColumns);
}
function mapToId(columns) {
columns
.forEach(function (column) {
columnsById[column.id] = column;
if (column.columns)
mapToId(column.columns);
});
}
function filter(node, condition) {
return node.filter(function (column) {
var valid = condition.call(column);
if (valid && column.columns)
column.columns = filter(column.columns, condition);
return valid && (!column.columns || column.columns.length);
});
}
function sort(columns, grid) {
columns
.sort(function (a, b) {
var indexA = getOrDefault(grid.getColumnIndex(a.id)),
indexB = getOrDefault(grid.getColumnIndex(b.id));
return indexA - indexB;
})
.forEach(function (column) {
if (column.columns)
sort(column.columns, grid);
});
}
function getOrDefault(value) {
return typeof value === 'undefined' ? -1 : value;
}
function getDepth(node) {
if (node.length)
for (var i in node)
return getDepth(node[i]);
else if (node.columns)
return 1 + getDepth(node.columns);
else
return 1;
}
function getColumnsInDepth(node, depth, current) {
var columns = [];
current = current || 0;
if (depth == current) {
if (node.length)
node.forEach(function(n) {
if (n.columns)
n.extractColumns = function() {
return extractColumns(n);
};
});
return node;
} else
for (var i in node)
if (node[i].columns) {
columns = columns.concat(getColumnsInDepth(node[i].columns, depth, current + 1));
}
return columns;
}
function extractColumns(node) {
var result = [];
if (node.hasOwnProperty('length')) {
for (var i = 0; i < node.length; i++)
result = result.concat(extractColumns(node[i]));
} else {
if (node.hasOwnProperty('columns'))
result = result.concat(extractColumns(node.columns));
else
return node;
}
return result;
}
function cloneTreeColumns() {
return $.extend(true, [], treeColumns);
}
init();
this.hasDepth = function () {
for (var i in treeColumns)
if (treeColumns[i].hasOwnProperty('columns'))
return true;
return false;
};
this.getTreeColumns = function () {
return treeColumns;
};
this.extractColumns = function () {
return this.hasDepth()? extractColumns(treeColumns): treeColumns;
};
this.getDepth = function () {
return getDepth(treeColumns);
};
this.getColumnsInDepth = function (depth) {
return getColumnsInDepth(treeColumns, depth);
};
this.getColumnsInGroup = function (groups) {
return extractColumns(groups);
};
this.visibleColumns = function () {
return filter(cloneTreeColumns(), function () {
return this.visible;
});
};
this.filter = function (condition) {
return filter(cloneTreeColumns(), condition);
};
this.reOrder = function (grid) {
return sort(treeColumns, grid);
};
this.getById = function (id) {
return columnsById[id];
};
this.getInIds = function (ids) {
return ids.map(function (id) {
return columnsById[id];
});
}
}
})(jQuery);

@@ -30,9 +30,6 @@ /***

this.init = function () {
var navOnLR = args.grid.getOptions().editorCellNavOnLRKeys;
$input = $("<INPUT type=text class='editor-text' />")
.appendTo(args.container)
.on("keydown.nav", function (e) {
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
e.stopImmediatePropagation();
}
})
.on("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav)
.focus()

@@ -100,12 +97,8 @@ .select();

this.init = function () {
$input = $("<INPUT type=text class='editor-text' />");
$input.on("keydown.nav", function (e) {
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
e.stopImmediatePropagation();
}
});
$input.appendTo(args.container);
$input.focus().select();
var navOnLR = args.grid.getOptions().editorCellNavOnLRKeys;
$input = $("<INPUT type=text class='editor-text' />")
.appendTo(args.container)
.on("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav)
.focus()
.select();
};

@@ -170,12 +163,8 @@

this.init = function () {
$input = $("<INPUT type=text class='editor-text' />");
$input.on("keydown.nav", function (e) {
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
e.stopImmediatePropagation();
}
});
$input.appendTo(args.container);
$input.focus().select();
var navOnLR = args.grid.getOptions().editorCellNavOnLRKeys;
$input = $("<INPUT type=text class='editor-text' />")
.appendTo(args.container)
.on("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav)
.focus()
.select();
};

@@ -222,3 +211,3 @@

}
var decPlaces = getDecimalPlaces();

@@ -547,2 +536,3 @@ if (decPlaces !== null

var $container = $("body");
var navOnLR = args.grid.getOptions().editorCellNavOnLRKeys;

@@ -560,3 +550,3 @@ $wrapper = $("<DIV style='z-index:10000;position:absolute;background:white;padding:5px;border:3px solid gray; -moz-border-radius:10px; border-radius:10px;'/>")

$wrapper.find("button:last").on("click", this.cancel);
$input.on("keydown", this.handleKeyDown);
$input.on("keydown", this.handleKeyDown);

@@ -579,2 +569,13 @@ scope.position(args.position);

args.grid.navigateNext();
} else if (e.which == $.ui.keyCode.LEFT || e.which == $.ui.keyCode.RIGHT) {
if (args.grid.getOptions().editorCellNavOnLRKeys) {
var cursorPosition = this.selectionStart;
var textLength = this.value.length;
if (e.keyCode === $.ui.keyCode.LEFT && cursorPosition === 0) {
args.grid.navigatePrev();
}
if (e.keyCode === $.ui.keyCode.RIGHT && cursorPosition >= textLength-1) {
args.grid.navigateNext();
}
}
}

@@ -647,2 +648,23 @@ };

}
/*
* Depending on the value of Grid option 'editorCellNavOnLRKeys', us
* Navigate to the cell on the left if the cursor is at the beginning of the input string
* and to the right cell if it's at the end. Otherwise, move the cursor within the text
*/
function handleKeydownLRNav(e) {
var cursorPosition = this.selectionStart;
var textLength = this.value.length;
if ((e.keyCode === $.ui.keyCode.LEFT && cursorPosition > 0) ||
e.keyCode === $.ui.keyCode.RIGHT && cursorPosition < textLength-1) {
e.stopImmediatePropagation();
}
}
function handleKeydownLRNoNav(e) {
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
e.stopImmediatePropagation();
}
}
})(jQuery);

@@ -47,3 +47,3 @@ (function ($) {

function defaultGroupCellFormatter(row, cell, value, columnDef, item) {
function defaultGroupCellFormatter(row, cell, value, columnDef, item, grid) {
if (!options.enableExpandCollapse) {

@@ -66,4 +66,4 @@ return item.title;

function defaultTotalsCellFormatter(row, cell, value, columnDef, item) {
return (columnDef.groupTotalsFormatter && columnDef.groupTotalsFormatter(item, columnDef)) || "";
function defaultTotalsCellFormatter(row, cell, value, columnDef, item, grid) {
return (columnDef.groupTotalsFormatter && columnDef.groupTotalsFormatter(item, columnDef, grid)) || "";
}

@@ -117,3 +117,3 @@

function handleGridKeyDown(e, args) {
if (options.enableExpandCollapse && (e.which == $.ui.keyCode.SPACE)) {
if (options.enableExpandCollapse && (e.which == Slick.keyCode.SPACE)) {
var activeCell = this.getActiveCell();

@@ -120,0 +120,0 @@ if (activeCell) {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc