diff --git a/controls/slick.gridmenu.js b/controls/slick.gridmenu.js index b362f79e..ae88dfe7 100644 --- a/controls/slick.gridmenu.js +++ b/controls/slick.gridmenu.js @@ -401,7 +401,7 @@ // notify of the onBeforeMenuShow only works when it's a jQuery event (as per slick.core code) // this mean that we cannot notify when the grid menu is attach to a button event if (typeof e.isPropagationStopped === "function") { - if (_self.onBeforeMenuShow.notify(callbackArgs, e, _self) == false) { + if (_self.onBeforeMenuShow.notify(callbackArgs, e, _self).getReturnValue() == false) { return; } } @@ -490,7 +490,7 @@ _isMenuOpen = true; if (typeof e.isPropagationStopped === "function") { - if (_self.onAfterMenuShow.notify(callbackArgs, e, _self) == false) { + if (_self.onAfterMenuShow.notify(callbackArgs, e, _self).getReturnValue() == false) { return; } } @@ -549,7 +549,7 @@ "allColumns": columns, "visibleColumns": getVisibleColumns() }; - if (_self.onMenuClose.notify(callbackArgs, e, _self) == false) { + if (_self.onMenuClose.notify(callbackArgs, e, _self).getReturnValue() == false) { return; } } diff --git a/cypress/integration/example-plugin-custom-tooltip.spec.js b/cypress/integration/example-plugin-custom-tooltip.spec.js index 51e1399e..202bc931 100644 --- a/cypress/integration/example-plugin-custom-tooltip.spec.js +++ b/cypress/integration/example-plugin-custom-tooltip.spec.js @@ -33,7 +33,7 @@ describe('Example - Custom Tooltip', () => { cy.get('@checkbox0-cell').trigger('mouseover'); cy.get('.slick-custom-tooltip').should('not.exist'); - cy.get('@checkbox0-cell').trigger('mouseleave'); + cy.get('@checkbox0-cell').trigger('mouseout'); }); it('should mouse over Task 1 cell and expect async tooltip to show', () => { @@ -52,7 +52,7 @@ describe('Example - Custom Tooltip', () => { cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(0)').contains('Ratio:'); cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(1)').contains(/\d+$/); // use regexp to make sure it's a number - cy.get('@task1-cell').trigger('mouseleave'); + cy.get('@task1-cell').trigger('mouseout'); }); it('should mouse over Task 5 cell and expect async tooltip to show', () => { @@ -71,7 +71,7 @@ describe('Example - Custom Tooltip', () => { cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(0)').contains('Ratio:'); cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(1)').contains(/\d+$/); // use regexp to make sure it's a number - cy.get('@task5-cell').trigger('mouseleave'); + cy.get('@task5-cell').trigger('mouseout'); }); it('should mouse over 6th row Description and expect full cell content to show in a tooltip because cell has ellipsis and is too long for the cell itself', () => { @@ -83,7 +83,7 @@ describe('Example - Custom Tooltip', () => { cy.get('.slick-custom-tooltip').should('not.contain', `regular tooltip (from title attribute)\nTask 5 cell value:\nThis is a sample task description.\nIt can be multiline\n\nAnother line...`); cy.get('.slick-custom-tooltip').should('contain', `This is a sample task description.\nIt can be multiline\n\nAnother line...`); - cy.get('@desc5-cell').trigger('mouseleave'); + cy.get('@desc5-cell').trigger('mouseout'); }); it('should mouse over 6th row Description 2 and expect regular tooltip title + concatenated full cell content when using "useRegularTooltipFromFormatterOnly: true"', () => { @@ -94,7 +94,7 @@ describe('Example - Custom Tooltip', () => { cy.get('.slick-custom-tooltip').should('be.visible'); cy.get('.slick-custom-tooltip').should('contain', `regular tooltip (from title attribute)\nTask 5 cell value:\nThis is a sample task description.\nIt can be multiline\n\nAnother line...`); - cy.get('@desc2-5-cell').trigger('mouseleave'); + cy.get('@desc2-5-cell').trigger('mouseout'); }); it('should mouse over 6th row Duration and expect a custom tooltip shown with 4 label/value pairs displayed', () => { @@ -118,7 +118,7 @@ describe('Example - Custom Tooltip', () => { cy.get('.tooltip-2cols-row:nth(3)').find('div:nth(1)') .find('img').invoke('attr', 'src').then(src => expect(src).to.contain('tick.png')); - cy.get('@duration5-cell').trigger('mouseleave'); + cy.get('@duration5-cell').trigger('mouseout'); }); it('should mouse over % Complete cell of Task 5 and expect regular tooltip to show with content "x %" where x is a number', () => { @@ -129,12 +129,12 @@ describe('Example - Custom Tooltip', () => { cy.get('.slick-custom-tooltip').should('be.visible'); cy.get('.slick-custom-tooltip').contains(/\d+\%$/); - cy.get('@percentage-cell').trigger('mouseleave'); + cy.get('@percentage-cell').trigger('mouseout'); }); it('should mouse over header-row (filter) 1st column checkbox and NOT expect any tooltip to show since it is disabled on that column', () => { cy.get(`.slick-headerrow-columns .slick-headerrow-column:nth(0)`).as('checkbox0-filter') - cy.get('@checkbox0-filter').trigger('mouseover'); + cy.get('@checkbox0-filter').trigger('mouseenter'); cy.get('.slick-custom-tooltip').should('not.exist'); cy.get('@checkbox0-filter').trigger('mouseleave'); @@ -142,7 +142,7 @@ describe('Example - Custom Tooltip', () => { it('should mouse over header-row (filter) 2nd column Title and expect a tooltip to show rendered from an headerRowFormatter', () => { cy.get(`.slick-headerrow-columns .slick-headerrow-column:nth(1)`).as('checkbox0-filter') - cy.get('@checkbox0-filter').trigger('mouseover'); + cy.get('@checkbox0-filter').trigger('mouseenter'); cy.get('.slick-custom-tooltip').should('be.visible'); cy.get('.slick-custom-tooltip').contains('Custom Tooltip - Header Row (filter)'); @@ -155,7 +155,7 @@ describe('Example - Custom Tooltip', () => { it('should mouse over header-row (filter) Finish column and NOT expect any tooltip to show since it is disabled on that column', () => { cy.get(`.slick-headerrow-columns .slick-headerrow-column:nth(7)`).as('finish-filter') - cy.get('@finish-filter').trigger('mouseover'); + cy.get('@finish-filter').trigger('mouseenter'); cy.get('.slick-custom-tooltip').should('not.exist'); cy.get('@finish-filter').trigger('mouseleave'); @@ -163,7 +163,7 @@ describe('Example - Custom Tooltip', () => { it('should mouse over header title on 1st column with checkbox and NOT expect any tooltip to show since it is disabled on that column', () => { cy.get(`.slick-header-columns .slick-header-column:nth(0)`).as('checkbox-header') - cy.get('@checkbox-header').trigger('mouseover'); + cy.get('@checkbox-header').trigger('mouseenter'); cy.get('.slick-custom-tooltip').should('not.exist'); cy.get('@checkbox-header').trigger('mouseleave'); @@ -171,7 +171,7 @@ describe('Example - Custom Tooltip', () => { it('should mouse over header title on 2nd column with Title name and expect a tooltip to show rendered from an headerFormatter', () => { cy.get(`.slick-header-columns .slick-header-column:nth(1)`).as('checkbox0-header') - cy.get('@checkbox0-header').trigger('mouseover'); + cy.get('@checkbox0-header').trigger('mouseenter'); cy.get('.slick-custom-tooltip').should('be.visible'); cy.get('.slick-custom-tooltip').contains('Custom Tooltip - Header'); @@ -184,7 +184,7 @@ describe('Example - Custom Tooltip', () => { it('should mouse over header title on 2nd column with Finish name and NOT expect any tooltip to show since it is disabled on that column', () => { cy.get(`.slick-header-columns .slick-header-column:nth(7)`).as('finish-header') - cy.get('@finish-header').trigger('mouseover'); + cy.get('@finish-header').trigger('mouseenter'); cy.get('.slick-custom-tooltip').should('not.exist'); cy.get('@finish-header').trigger('mouseleave'); diff --git a/examples/example-checkbox-header-row.html b/examples/example-checkbox-header-row.html index 521a6f3c..94a49cba 100644 --- a/examples/example-checkbox-header-row.html +++ b/examples/example-checkbox-header-row.html @@ -118,12 +118,12 @@

Selected Ids (0) with index/id offset= + - diff --git a/examples/example-column-group.html b/examples/example-column-group.html index 8feabe59..04851404 100644 --- a/examples/example-column-group.html +++ b/examples/example-column-group.html @@ -94,46 +94,44 @@

View Source:

{id: "effort-driven", name: "Effort Driven", width: 80, minWidth: 20, maxWidth: 80, field: "effortDriven", columnGroup:"Analysis"} ]; - $(function () { - for (var i = 0; i < 50000; i++) { - var d = (data[i] = {}); + for (var i = 0; i < 50000; i++) { + var d = (data[i] = {}); - d["id"] = "id_" + i; - d["num"] = i; - d["title"] = "Task " + i; - d["duration"] = "5 days"; - d["start"] = "01/01/2009"; - d["finish"] = "01/05/2009"; - d["percentComplete"] = Math.round(Math.random() * 100); - d["effortDriven"] = (i % 5 == 0); - } + d["id"] = "id_" + i; + d["num"] = i; + d["title"] = "Task " + i; + d["duration"] = "5 days"; + d["start"] = "01/01/2009"; + d["finish"] = "01/05/2009"; + d["percentComplete"] = Math.round(Math.random() * 100); + d["effortDriven"] = (i % 5 == 0); + } - dataView = new Slick.Data.DataView(); - grid = new Slick.Grid("#myGrid", dataView, columns, options); + dataView = new Slick.Data.DataView(); + grid = new Slick.Grid("#myGrid", dataView, columns, options); - dataView.onRowCountChanged.subscribe(function (e, args) { - grid.updateRowCount(); - grid.render(); - }); + dataView.onRowCountChanged.subscribe(function (e, args) { + grid.updateRowCount(); + grid.render(); + }); - dataView.onRowsChanged.subscribe(function (e, args) { - grid.invalidateRows(args.rows); - grid.render(); - }); + dataView.onRowsChanged.subscribe(function (e, args) { + grid.invalidateRows(args.rows); + grid.render(); + }); - grid.init(); + grid.init(); - grid.onColumnsResized.subscribe(function (e, args) { - CreateAddlHeaderRow(); - }); - + grid.onColumnsResized.subscribe(function (e, args) { CreateAddlHeaderRow(); - - // Initialise data - dataView.beginUpdate(); - dataView.setItems(data); - dataView.endUpdate(); - }) + }); + + CreateAddlHeaderRow(); + + // Initialise data + dataView.beginUpdate(); + dataView.setItems(data); + dataView.endUpdate(); diff --git a/examples/example-composite-editor-item-details.html b/examples/example-composite-editor-item-details.html index 031b6a92..922f5118 100644 --- a/examples/example-composite-editor-item-details.html +++ b/examples/example-composite-editor-item-details.html @@ -157,11 +157,11 @@

View Source:

.appendTo("body"); $modal.keydown(function (e) { - if (e.which == $.ui.keyCode.ENTER) { + if (e.which == Slick.keyCode.ENTER) { grid.getEditController().commitCurrentEdit(); e.stopPropagation(); e.preventDefault(); - } else if (e.which == $.ui.keyCode.ESCAPE) { + } else if (e.which == Slick.keyCode.ESCAPE) { grid.getEditController().cancelCurrentEdit(); e.stopPropagation(); e.preventDefault(); @@ -178,7 +178,7 @@

View Source:

var containers = $.map(columns, function (c) { - return $modal.find("[data-editorid=" + c.id + "]"); + return $modal.find("[data-editorid=" + c.id + "]")[0]; }); var compositeEditor = new Slick.CompositeEditor( diff --git a/examples/example-composite-editor-modal-dialog.html b/examples/example-composite-editor-modal-dialog.html index 4d793fcb..d8d2656e 100644 --- a/examples/example-composite-editor-modal-dialog.html +++ b/examples/example-composite-editor-modal-dialog.html @@ -439,7 +439,7 @@

View Source:

}); var containers = $.map(modalColumns, function (c) { - return $modal.find("[data-editorid=" + c.id + "]"); + return $modal.find("[data-editorid=" + c.id + "]")[0]; }); var compositeEditor = new Slick.CompositeEditor( diff --git a/examples/example-explicit-initialization.html b/examples/example-explicit-initialization.html index 99cc2aa0..cb170b7a 100644 --- a/examples/example-explicit-initialization.html +++ b/examples/example-explicit-initialization.html @@ -72,7 +72,7 @@

View Source:

// create a detached container element var myGrid = $("
"); - grid = new Slick.Grid(myGrid, data, columns, options); + grid = new Slick.Grid(myGrid[0], data, columns, options); // ... later on, append the container to the DOM and initialize SlickGrid diff --git a/examples/example1-simple.html b/examples/example1-simple.html index b188a225..acdcc68d 100644 --- a/examples/example1-simple.html +++ b/examples/example1-simple.html @@ -26,8 +26,6 @@

View Source:

- - @@ -50,21 +48,19 @@

View Source:

enableColumnReorder: false }; - $(function () { - var data = []; - for (var i = 0; i < 500; i++) { - data[i] = { - title: "Task " + i, - duration: "5 days", - percentComplete: Math.round(Math.random() * 100), - start: "01/01/2009", - finish: "01/05/2009", - effortDriven: (i % 5 == 0) - }; - } + var data = []; + for (var i = 0; i < 500; i++) { + data[i] = { + title: "Task " + i, + duration: "5 days", + percentComplete: Math.round(Math.random() * 100), + start: "01/01/2009", + finish: "01/05/2009", + effortDriven: (i % 5 == 0) + }; + } - grid = new Slick.Grid("#myGrid", data, columns, options); - }) + grid = new Slick.Grid("#myGrid", data, columns, options); diff --git a/examples/example2-formatters.html b/examples/example2-formatters.html index 52561d71..b8d3943c 100644 --- a/examples/example2-formatters.html +++ b/examples/example2-formatters.html @@ -49,7 +49,6 @@

View Source:

- @@ -99,10 +98,10 @@

View Source:

var options = { editable: true, enableAddRow: false, - enableCellNavigation: true + enableCellNavigation: true, + createPreHeaderPanel: true }; - $(function () { for (var i = 0; i < 5; i++) { var d = (data[i] = {}); @@ -115,7 +114,6 @@

View Source:

} grid = new Slick.Grid("#myGrid", data, columns, options); - }) diff --git a/examples/example3-editing.html b/examples/example3-editing.html index fc60a7dd..944d6f9d 100644 --- a/examples/example3-editing.html +++ b/examples/example3-editing.html @@ -53,10 +53,10 @@

View Source:

- - - + + + diff --git a/examples/example3b-editing-with-undo.html b/examples/example3b-editing-with-undo.html index d5d07854..8f8c6b16 100644 --- a/examples/example3b-editing-with-undo.html +++ b/examples/example3b-editing-with-undo.html @@ -41,7 +41,6 @@

View Source:

- @@ -96,7 +95,6 @@

View Source:

} } - $(function () { for (var i = 0; i < 500; i++) { var d = (data[i] = {}); @@ -110,7 +108,6 @@

View Source:

} grid = new Slick.Grid("#myGrid", data, columns, options); - }) diff --git a/examples/example5-collapsing-treeGrid-sort.html b/examples/example5-collapsing-treeGrid-sort.html index bf1acbdd..cccb988d 100644 --- a/examples/example5-collapsing-treeGrid-sort.html +++ b/examples/example5-collapsing-treeGrid-sort.html @@ -65,8 +65,6 @@

View Source:

- - @@ -606,12 +604,12 @@

View Source:

"start": "01/01/2009", "finish": "01/01/2009", "effortDriven": false}; - $.extend(item, args.item); + Slick.Utils.extend(item, args.item); dataView.addItem(item); }); grid.onClick.subscribe(function (e, args) { - if ($(e.target).hasClass("toggle")) { + if (e.getNativeEvent().target.classList.contains("toggle")) { var item = dataView.getItem(args.row); if (item) { if (!item._collapsed) { @@ -657,7 +655,7 @@

View Source:

// wire up the search textbox to apply the filter to the model - $("#txtSearch").keyup(function (e) { + document.getElementById("txtSearch").addEventListener("keyup", function (e) { Slick.GlobalEditorLock.cancelCurrentEdit(); // clear on Esc @@ -670,33 +668,27 @@

View Source:

}) } -$(function () { - // $.ajaxSettings.async = false; - // $.getJSON("./data.json",function(content){ - // data = content; - // }); - // $.ajaxSettings.async = true; - - let indent = 0; - let parents = []; - - itemMap = groupBy(data, 'parentId'); - data = initTree(data); - - // initialize the model - dataView = new Slick.Data.DataView({ inlineFilters: true }); - dataView.beginUpdate(); - dataView.setItems(data); - dataView.setFilter(myFilter); - dataView.endUpdate(); - - // initialize the grid - grid = new Slick.Grid("#myGrid", dataView, columns, options); +let indent = 0; +let parents = []; + +itemMap = groupBy(data, 'parentId'); +data = initTree(data); + +// initialize the model +dataView = new Slick.Data.DataView({ inlineFilters: true }); +dataView.beginUpdate(); +dataView.setItems(data); +dataView.setFilter(myFilter); +dataView.endUpdate(); + + +// initialize the grid +grid = new Slick.Grid("#myGrid", dataView, columns, options); + +bindGridEvents(); - bindGridEvents(); -}) diff --git a/examples/example5-collapsing.html b/examples/example5-collapsing.html index 819ef932..44e85ce2 100644 --- a/examples/example5-collapsing.html +++ b/examples/example5-collapsing.html @@ -66,7 +66,6 @@

View Source:

- @@ -154,128 +153,126 @@

View Source:

return a["percentComplete"] - b["percentComplete"]; } -$(function () { - var indent = 0; - var parents = []; - - // prepare the data - for (var i = 0; i < 1000; i++) { - var d = (data[i] = {}); - var parent; - - if (Math.random() > 0.8 && i > 0) { - indent++; - parents.push(i - 1); - } else if (Math.random() < 0.3 && indent > 0) { - indent--; - parents.pop(); - } - - if (parents.length > 0) { - parent = parents[parents.length - 1]; - } else { - parent = null; - } +var indent = 0; +var parents = []; + +// prepare the data +for (var i = 0; i < 1000; i++) { + var d = (data[i] = {}); + var parent; + + if (Math.random() > 0.8 && i > 0) { + indent++; + parents.push(i - 1); + } else if (Math.random() < 0.3 && indent > 0) { + indent--; + parents.pop(); + } - d["id"] = "id_" + i; - d["indent"] = indent; - d["parent"] = parent; - d["title"] = "Task " + i; - d["duration"] = "5 days"; - d["percentComplete"] = Math.round(Math.random() * 100); - d["start"] = "01/01/2009"; - d["finish"] = "01/05/2009"; - d["effortDriven"] = (i % 5 == 0); + if (parents.length > 0) { + parent = parents[parents.length - 1]; + } else { + parent = null; } + d["id"] = "id_" + i; + d["indent"] = indent; + d["parent"] = parent; + d["title"] = "Task " + i; + d["duration"] = "5 days"; + d["percentComplete"] = Math.round(Math.random() * 100); + d["start"] = "01/01/2009"; + d["finish"] = "01/05/2009"; + d["effortDriven"] = (i % 5 == 0); +} + - // initialize the model - dataView = new Slick.Data.DataView({ inlineFilters: true }); - dataView.beginUpdate(); - dataView.setItems(data); - dataView.setFilter(myFilter); - dataView.endUpdate(); - - - // initialize the grid - grid = new Slick.Grid("#myGrid", dataView, columns, options); - - grid.onCellChange.subscribe(function (e, args) { - dataView.updateItem(args.item.id, args.item); - }); - - grid.onAddNewRow.subscribe(function (e, args) { - var item = { - "id": "new_" + (Math.round(Math.random() * 10000)), - "indent": 0, - "title": "New task", - "duration": "1 day", - "percentComplete": 0, - "start": "01/01/2009", - "finish": "01/01/2009", - "effortDriven": false}; - $.extend(item, args.item); - dataView.addItem(item); - }); - - grid.onClick.subscribe(function (e, args) { - if ($(e.target).hasClass("toggle")) { - var item = dataView.getItem(args.row); - if (item) { - if (!item._collapsed) { - item._collapsed = true; - } else { - item._collapsed = false; - } - - dataView.updateItem(item.id, item); +// initialize the model +dataView = new Slick.Data.DataView({ inlineFilters: true }); +dataView.beginUpdate(); +dataView.setItems(data); +dataView.setFilter(myFilter); +dataView.endUpdate(); + + +// initialize the grid +grid = new Slick.Grid("#myGrid", dataView, columns, options); + +grid.onCellChange.subscribe(function (e, args) { + dataView.updateItem(args.item.id, args.item); +}); + +grid.onAddNewRow.subscribe(function (e, args) { + var item = { + "id": "new_" + (Math.round(Math.random() * 10000)), + "indent": 0, + "title": "New task", + "duration": "1 day", + "percentComplete": 0, + "start": "01/01/2009", + "finish": "01/01/2009", + "effortDriven": false}; + Slick.Utils.extend(item, args.item); + dataView.addItem(item); +}); + +grid.onClick.subscribe(function (e, args) { + if (e.getNativeEvent().target.classList.contains("toggle")) { + var item = dataView.getItem(args.row); + if (item) { + if (!item._collapsed) { + item._collapsed = true; + } else { + item._collapsed = false; } - e.stopImmediatePropagation(); + + dataView.updateItem(item.id, item); } - }); + e.stopImmediatePropagation(); + } +}); - // wire up model events to drive the grid - dataView.onRowCountChanged.subscribe(function (e, args) { - grid.updateRowCount(); - grid.render(); - }); +// wire up model events to drive the grid +dataView.onRowCountChanged.subscribe(function (e, args) { + grid.updateRowCount(); + grid.render(); +}); - dataView.onRowsChanged.subscribe(function (e, args) { - grid.invalidateRows(args.rows); - grid.render(); - }); +dataView.onRowsChanged.subscribe(function (e, args) { + grid.invalidateRows(args.rows); + grid.render(); +}); - var h_runfilters = null; +var h_runfilters = null; - // wire up the slider to apply the filter to the model - var slider = document.getElementById("pcSlider"); - var sliderCallback = function() { - Slick.GlobalEditorLock.cancelCurrentEdit(); +// wire up the slider to apply the filter to the model +var slider = document.getElementById("pcSlider"); +var sliderCallback = function() { + Slick.GlobalEditorLock.cancelCurrentEdit(); - if (percentCompleteThreshold != this.value) { - window.clearTimeout(h_runfilters); - h_runfilters = window.setTimeout(dataView.refresh, 10); - percentCompleteThreshold = this.value; - } + if (percentCompleteThreshold != this.value) { + window.clearTimeout(h_runfilters); + h_runfilters = window.setTimeout(dataView.refresh, 10); + percentCompleteThreshold = this.value; } - - slider.oninput = sliderCallback; +} - // wire up the search textbox to apply the filter to the model - $("#txtSearch").keyup(function (e) { - Slick.GlobalEditorLock.cancelCurrentEdit(); +slider.oninput = sliderCallback; - // clear on Esc - if (e.which == 27) { - this.value = ""; - } +// wire up the search textbox to apply the filter to the model +document.getElementById("txtSearch").addEventListener("keyup", function (e) { + Slick.GlobalEditorLock.cancelCurrentEdit(); + + // clear on Esc + if (e.which == 27) { + this.value = ""; + } - searchString = this.value; - dataView.refresh(); - }) -}) + searchString = this.value; + dataView.refresh(); +}); diff --git a/plugins/slick.cellmenu.js b/plugins/slick.cellmenu.js index 6dd28b21..f180b18f 100644 --- a/plugins/slick.cellmenu.js +++ b/plugins/slick.cellmenu.js @@ -206,7 +206,7 @@ "cell": _currentCell, "row": _currentRow, "grid": _grid - }, e, _self) == false) { + }, e, _self).getReturnValue() == false) { return; } @@ -259,7 +259,7 @@ "cell": _currentCell, "row": _currentRow, "grid": _grid - }, e, _self) == false) { + }, e, _self).getReturnValue() == false) { return; } @@ -301,7 +301,7 @@ "row": args && args.row, "grid": _grid, "menu": $menu - }, e, _self) == false) { + }, e, _self).getReturnValue() == false) { return; } } @@ -364,6 +364,9 @@ } function handleCellClick(e, args) { + if(e instanceof Slick.EventData) + e = e.getNativeEvent(); + var cell = _grid.getCellFromEvent(e); var dataContext = _grid.getDataItem(cell.row); var columnDef = _grid.getColumns()[cell.cell]; @@ -418,7 +421,7 @@ "row": args && args.row, "grid": _grid, "menu": $menu - }, e, _self) == false) { + }, e, _self).getReturnValue() == false) { return; } if ($menu && $menu.remove) { diff --git a/plugins/slick.cellrangeselector.js b/plugins/slick.cellrangeselector.js index 250d0d65..ea417bf1 100644 --- a/plugins/slick.cellrangeselector.js +++ b/plugins/slick.cellrangeselector.js @@ -151,14 +151,15 @@ return _decorator.show(new Slick.Range(start.row, start.cell)); } - function handleDrag(e, dd) { + function handleDrag(evt, dd) { if (!_dragging && !_isRowMoveRegistered) { return; } if (!_isRowMoveRegistered) { - e.stopImmediatePropagation(); + evt.stopImmediatePropagation(); } + const e = evt.getNativeEvent(); if (options.autoScroll) { _draggingMouseOffset = getMouseOffsetViewport(e, dd); if (_draggingMouseOffset.isOutsideViewport) { diff --git a/plugins/slick.cellselectionmodel.js b/plugins/slick.cellselectionmodel.js index 90201c76..69eec116 100644 --- a/plugins/slick.cellselectionmodel.js +++ b/plugins/slick.cellselectionmodel.js @@ -92,7 +92,7 @@ _ranges = removeInvalidRanges(ranges); if (rangeHasChanged) { // provide extra "caller" argument through SlickEventData to avoid breaking pubsub event that only accepts an array of selected range - var eventData = new Slick.EventData(); + var eventData = new Slick.EventData(null, _ranges); Object.defineProperty(eventData, 'detail', { writable: true, configurable: true, value: { caller: caller || "SlickCellSelectionModel.setSelectedRanges" } }); _self.onSelectedRangesChanged.notify(_ranges, eventData); } diff --git a/plugins/slick.contextmenu.js b/plugins/slick.contextmenu.js index 1b92d126..5f1783a4 100644 --- a/plugins/slick.contextmenu.js +++ b/plugins/slick.contextmenu.js @@ -200,6 +200,9 @@ } function createMenu(e) { + if(e instanceof Slick.EventData) + e = e.getNativeEvent(); + var targetEvent = e.touches ? e.touches[0] : e; var cell = _grid.getCellFromEvent(e); _currentCell = cell && cell.cell; @@ -226,7 +229,7 @@ "cell": _currentCell, "row": _currentRow, "grid": _grid - }, e, _self) == false) { + }, e, _self).getReturnValue() == false) { return; } @@ -279,7 +282,7 @@ "cell": _currentCell, "row": _currentRow, "grid": _grid - }, e, _self) == false) { + }, e, _self).getReturnValue() == false) { return; } @@ -301,7 +304,7 @@ "row": args && args.row, "grid": _grid, "menu": $menu - }, e, _self) == false) { + }, e, _self).getReturnValue() == false) { return; } if ($menu && $menu.remove) { @@ -346,6 +349,9 @@ } function handleOnContextMenu(e, args) { + if(e instanceof Slick.EventData) + e = e.getNativeEvent(); + e.preventDefault(); var cell = _grid.getCellFromEvent(e); diff --git a/plugins/slick.crossgridrowmovemanager.js b/plugins/slick.crossgridrowmovemanager.js index 04edbb40..ca88a474 100644 --- a/plugins/slick.crossgridrowmovemanager.js +++ b/plugins/slick.crossgridrowmovemanager.js @@ -147,12 +147,13 @@ dd.insertBefore = -1; } - function handleDrag(e, dd) { + function handleDrag(evt, dd) { if (!_dragging) { return; } - e.stopImmediatePropagation(); + evt.stopImmediatePropagation(); + const e = evt.getNativeEvent(); var top = e.pageY - $(_toCanvas).offset().top; dd.selectionProxy.css("top", top - 5).show(); @@ -172,7 +173,7 @@ "insertBefore": insertBefore }; - if (_self.onBeforeMoveRows.notify(eventData) === false) { + if (_self.onBeforeMoveRows.notify(eventData).getReturnValue() === false) { dd.canMove = false; } else { dd.canMove = true; diff --git a/plugins/slick.headermenu.js b/plugins/slick.headermenu.js index 9dfbb0dd..af48b18b 100644 --- a/plugins/slick.headermenu.js +++ b/plugins/slick.headermenu.js @@ -213,7 +213,7 @@ "column": columnDef, "menu": menu }; - if (_self.onBeforeMenuShow.notify(callbackArgs, e, _self) == false) { + if (_self.onBeforeMenuShow.notify(callbackArgs, e, _self).getReturnValue() == false) { return; } @@ -316,7 +316,7 @@ $activeHeaderColumn .addClass("slick-header-column-active"); - if (_self.onAfterMenuShow.notify(callbackArgs, e, _self) == false) { + if (_self.onAfterMenuShow.notify(callbackArgs, e, _self).getReturnValue() == false) { return; } diff --git a/plugins/slick.rowmovemanager.js b/plugins/slick.rowmovemanager.js index 59e777d3..3d61a462 100644 --- a/plugins/slick.rowmovemanager.js +++ b/plugins/slick.rowmovemanager.js @@ -138,12 +138,13 @@ dd.insertBefore = -1; } - function handleDrag(e, dd) { + function handleDrag(evt, dd) { if (!_dragging) { return; } - e.stopImmediatePropagation(); + evt.stopImmediatePropagation(); + const e = evt.getNativeEvent(); var targetEvent = e.touches ? e.touches[0] : e; var top = targetEvent.pageY - $(_canvas).offset().top; @@ -163,7 +164,7 @@ "insertBefore": insertBefore }; - if (_self.onBeforeMoveRows.notify(eventData) === false) { + if (_self.onBeforeMoveRows.notify(eventData).getReturnValue() === false) { dd.canMove = false; } else { dd.canMove = true; diff --git a/plugins/slick.rowselectionmodel.js b/plugins/slick.rowselectionmodel.js index fe1f9bf8..ad6685da 100644 --- a/plugins/slick.rowselectionmodel.js +++ b/plugins/slick.rowselectionmodel.js @@ -126,7 +126,7 @@ _ranges = ranges; // provide extra "caller" argument through SlickEventData to avoid breaking pubsub event that only accepts an array of selected range - var eventData = new Slick.EventData(); + var eventData = new Slick.EventData(null, _ranges); Object.defineProperty(eventData, 'detail', { writable: true, configurable: true, value: { caller: caller || "SlickRowSelectionModel.setSelectedRanges" } }); _self.onSelectedRangesChanged.notify(_ranges, eventData); } diff --git a/slick.compositeeditor.js b/slick.compositeeditor.js index 71e0cb63..cd26388d 100644 --- a/slick.compositeeditor.js +++ b/slick.compositeeditor.js @@ -1,4 +1,4 @@ -(function ($) { +(function () { /*** * A composite SlickGrid editor factory. * Generates an editor that is composed of multiple editors for given columns. @@ -44,14 +44,14 @@ var firstInvalidEditor; - options = $.extend({}, defaultOptions, options); + options = Slick.Utils.extend({}, defaultOptions, options); function getContainerBox(i) { var c = containers[i]; - var offset = $(c).offset(); - var w = $(c).width() || 0; - var h = $(c).height() || 0; + var offset = Slick.Utils.offset(c); + var w = Slick.Utils.width(c); + var h = Slick.Utils.height(c); return { top: offset && offset.top, @@ -75,7 +75,7 @@ while (idx < columns.length) { if (columns[idx].editor) { var column = columns[idx]; - newArgs = $.extend({}, args); + newArgs = Slick.Utils.extend(false, {}, args); newArgs.container = containers[idx]; newArgs.column = column; newArgs.position = getContainerBox(idx); @@ -162,7 +162,7 @@ this.validate = function (targetElm) { var validationResults; var errors = []; - var $targetElm = targetElm ? $(targetElm) : null; + var targetElm = targetElm ? targetElm : null; firstInvalidEditor = null; @@ -170,12 +170,12 @@ while (idx < editors.length) { var columnDef = editors[idx].args && editors[idx].args.column || {}; if (columnDef) { - var $validationElm = $(".item-details-validation.editor-" + columnDef.id); - var $labelElm = $(".item-details-label.editor-" + columnDef.id); - var $editorElm = $("[data-editorid=" + columnDef.id + "]"); + var validationElm = document.querySelector(".item-details-validation.editor-" + columnDef.id); + var labelElm = document.querySelector(".item-details-label.editor-" + columnDef.id); + var editorElm = document.querySelector("[data-editorid=" + columnDef.id + "]"); var validationMsgPrefix = options && options.validationMsgPrefix || ""; - if (!$targetElm || ($editorElm.has($targetElm).length > 0)) { + if (!targetElm || Slick.Utils.contains(editorElm, targetElm)) { validationResults = editors[idx].validate(); if (!validationResults.valid) { @@ -187,24 +187,24 @@ msg: validationResults.msg }); - if ($validationElm) { - $validationElm.text(validationMsgPrefix + validationResults.msg); - $labelElm.addClass("invalid"); - $editorElm.addClass("invalid"); + if (validationElm) { + validationElm.textContent = validationMsgPrefix + validationResults.msg; + labelElm.classList.add("invalid"); + editorElm.classList.add("invalid"); } - } else if ($validationElm) { - $validationElm.text(""); - $editorElm.removeClass("invalid"); - $labelElm.removeClass("invalid"); + } else if (validationElm) { + validationElm.textContent = ""; + editorElm.classList.remove("invalid"); + labelElm.classList.remove("invalid"); } } - $validationElm = null; - $labelElm = null; - $editorElm = null; + validationElm = null; + labelElm = null; + editorElm = null; } idx++; } - $targetElm = null; + targetElm = null; if (errors.length) { return { @@ -255,9 +255,7 @@ } // exports - $.extend(true, window, { - Slick: { - CompositeEditor: CompositeEditor - } + Slick.Utils.extend(Slick, { + CompositeEditor: CompositeEditor }); -})(jQuery); \ No newline at end of file +})(); \ No newline at end of file diff --git a/slick.core.js b/slick.core.js index fc0aac35..a9313fe3 100644 --- a/slick.core.js +++ b/slick.core.js @@ -4,16 +4,24 @@ * @namespace Slick */ -(function ($) { +(function (window) { /*** * An event object for passing data to event handlers and letting them control propagation. *

This is pretty much identical to how W3C and jQuery implement events.

* @class EventData * @constructor */ - function EventData() { + function EventData(event, args) { + + var nativeEvent = event; + var arguments_ = args; var isPropagationStopped = false; var isImmediatePropagationStopped = false; + var isDefaultPrevented = false; + var returnValues = []; + var returnValue = undefined; + + this.target = nativeEvent ? nativeEvent.target : undefined; /*** * Stops event from propagating up the DOM tree. @@ -21,6 +29,9 @@ */ this.stopPropagation = function () { isPropagationStopped = true; + if(nativeEvent) { + nativeEvent.stopPropagation(); + } }; /*** @@ -38,6 +49,9 @@ */ this.stopImmediatePropagation = function () { isImmediatePropagationStopped = true; + if(nativeEvent) { + nativeEvent.stopImmediatePropagation(); + } }; /*** @@ -48,6 +62,39 @@ this.isImmediatePropagationStopped = function () { return isImmediatePropagationStopped; }; + + this.getNativeEvent = function() { + return nativeEvent; + } + + this.preventDefault = function() { + if(nativeEvent) { + nativeEvent.preventDefault(); + } + isDefaultPrevented = true; + } + + this.isDefaultPrevented = function() { + if(nativeEvent) { + return nativeEvent.defaultPrevented; + } + return isDefaultPrevented; + } + + this.addReturnValue = function(value) { + returnValues.push(value); + if(returnValue === undefined && value !== undefined) { + returnValue = value; + } + } + + this.getReturnValue = function() { + return returnValue; + } + + this.getArguments = function() { + return arguments_; + } } /*** @@ -96,15 +143,17 @@ * If not specified, the scope will be set to the Event instance. */ this.notify = function (args, e, scope) { - e = e || new EventData(); + + if(!(e instanceof EventData)) + e = new EventData(e, args); scope = scope || this; - var returnValue; for (var i = 0; i < handlers.length && !(e.isPropagationStopped() || e.isImmediatePropagationStopped()); i++) { - returnValue = handlers[i].call(scope, e, args); + const returnValue = handlers[i].call(scope, e, args); + e.addReturnValue(returnValue); } - return returnValue; + return e; }; } @@ -564,7 +613,7 @@ } function cloneTreeColumns() { - return $.extend(true, [], treeColumns); + return extend([], treeColumns); } init(); @@ -572,8 +621,10 @@ this.hasDepth = function () { for (var i in treeColumns) + { if (treeColumns[i].hasOwnProperty('columns')) return true; + } return false; }; @@ -675,10 +726,251 @@ function regexSanitizer(dirtyHtml) { return dirtyHtml.replace(/(\b)(on[a-z]+)(\s*)=|javascript:([^>]*)[^>]*|(<\s*)(\/*)script([<>]*).*(<\s*)(\/*)script(>*)|(<)(\/*)(script|script defer)(.*)(>|>">)/gi, ''); } - - // exports - $.extend(true, window, { - "Slick": { + + // With help from https://youmightnotneedjquery.com/ + function grep( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + } + + function offset(el) { + + box = el.getBoundingClientRect(); + docElem = document.documentElement; + return { + top: box.top + window.pageYOffset - docElem.clientTop, + left: box.left + window.pageXOffset - docElem.clientLeft + }; + } + + function width(el, value) { + if (value === undefined) { + return el.getBoundingClientRect().width; + } + setStyleSize(el, "width", value); + } + + function height(el, value) { + if (value === undefined) { + return el.getBoundingClientRect().height; + } + setStyleSize(el, "height", value); + } + + function setStyleSize(el, style, val) { + if (typeof val === 'function') { + val = val(); + } + else if (typeof val === 'string') { + el.style[style] = val; + } + else { + el.style[style] = val + 'px'; + } + } + + function contains(parent, child) { + if(!parent || !child) { + return false; + } + + const parentList = parents(child); + return !parentList.every(function (p) { + if(parent == p) { + return false; + } + return true; + }); + } + + function isHidden(el) { + return el.offsetWidth === 0 && el.offsetHeight === 0; + } + + function parents(el, selector) { + const parents = []; + const visible = selector == ":visible"; + const hidden = selector == ":hidden"; + + while ((el = el.parentNode) && el !== document) { + + if(hidden) + { + if(isHidden(el)) { + parents.push(el); + } + } + else if (visible) + { + if(!isHidden(el)) { + parents.push(el); + } + } + else if (!selector || el.matches(selector)) + { + parents.push(el); + } + } + return parents; + } + + function template(html, parent) { + const template = document.createElement('template'); + template.innerHTML = html.trim(); + + const first = template.content.firstChild; + if(parent) + { + [].forEach.call(template.content.children, function (child) { + parent.appendChild(child); + }); + return first; + } + return first; + } + + function toFloat(value) { + var x = parseFloat(value) + if (isNaN(x)) { + return 0; + } + return x; + } + + function show(el, type) { + + type = type ? type : ""; + if(Array.isArray(el)) { + el.forEach(function (e) { + e.style.display = type; + }) + } + else { + el.style.display = type; + } + } + + function hide(el) { + if(Array.isArray(el)) { + el.forEach(function (e) { + e.style.display = "none"; + }); + } + else { + el.style.display = "none"; + } + } + + function slideUp(el, callback) { + if(window.jQuery !== undefined) { + window.jQuery(el).slideUp("fast", callback); + return; + } + + hide(el); + callback(); + } + + function slideDown(el, callback) { + if(window.jQuery !== undefined) { + window.jQuery(el).slideDown("fast", callback); + return; + } + + show(el); + callback(); + } + + // jQuery's extend + var getProto = Object.getPrototypeOf; + var class2type = {}; + var toString = class2type.toString; + var hasOwn = class2type.hasOwnProperty; + var fnToString = hasOwn.toString; + var ObjectFunctionString = fnToString.call( Object ); + function isFunction( obj ) { + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + function isPlainObject( obj ) { + var proto, Ctor; + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + if ( !proto ) { + return true; + } + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + } + function extend() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ], + i = 1, + length = arguments.length, + deep = true; + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[ i ] || {}; + i++; + } + else + { + target = target || {} + } + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + if ( i === length ) { + target = this; + i--; + } + for ( ; i < length; i++ ) { + if ( ( options = arguments[ i ] ) != null ) { + for ( name in options ) { + copy = options[ name ]; + if ( name === "__proto__" || target === copy ) { + continue; + } + if ( deep && copy && ( isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + target[ name ] = extend( deep, clone, copy ); + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + return target; + }; + + // exports + window.Slick = { "Event": Event, "EventData": EventData, "EventHandler": EventHandler, @@ -689,7 +981,46 @@ "GroupTotals": GroupTotals, "RegexSanitizer": regexSanitizer, "EditorLock": EditorLock, - + "Utils": + { + "extend": extend, + "grep": grep, + "offset": offset, + "height": height, + "width": width, + "setStyleSize": setStyleSize, + "contains": contains, + "template": template, + "toFloat": toFloat, + "parents": parents, + "show": show, + "hide": hide, + "slideUp": slideUp, + "slideDown": slideDown, + "storage": { + // https://stackoverflow.com/questions/29222027/vanilla-alternative-to-jquery-data-function-any-native-javascript-alternati + _storage: new WeakMap(), + put: function (element, key, obj) { + if (!this._storage.has(element)) { + this._storage.set(element, new Map()); + } + this._storage.get(element).set(key, obj); + }, + get: function (element, key) { + const el = this._storage.get(element); + if(el) + return el.get(key); + return null; + }, + remove: function (element, key) { + var ret = this._storage.get(element).delete(key); + if (!this._storage.get(element).size === 0) { + this._storage.delete(element); + } + return ret; + } + } + }, /*** * A global singleton editor lock. * @class GlobalEditorLock @@ -757,7 +1088,4 @@ HTML: 'HTML' } } - }); -})(jQuery); - - +})(window); diff --git a/slick.dataview.js b/slick.dataview.js index 345dbc29..d6dcc959 100644 --- a/slick.dataview.js +++ b/slick.dataview.js @@ -1,4 +1,4 @@ -(function ($) { +(function () { /*** * A sample Model implementation. * Provides a filtered view of the underlying data. @@ -78,7 +78,7 @@ var onGroupExpanded = new Slick.Event(); var onGroupCollapsed = new Slick.Event(); - options = $.extend(true, {}, defaults, options); + options = Slick.Utils.extend({}, defaults, options); /*** * Begins a bached update of the items in the data view. @@ -221,7 +221,7 @@ } function setPagingOptions(args) { - if (onBeforePagingInfoChanged.notify(getPagingInfo(), null, self) !== false) { + if (onBeforePagingInfoChanged.notify(getPagingInfo(), null, self).getReturnValue() !== false) { if (args.pageSize != undefined) { pagesize = args.pageSize; pagenum = pagesize ? Math.min(pagenum, Math.max(0, Math.ceil(totalRows / pagesize) - 1)) : 0; @@ -330,7 +330,7 @@ groupingInfos = (groupingInfo instanceof Array) ? groupingInfo : [groupingInfo]; for (var i = 0; i < groupingInfos.length; i++) { - var gi = groupingInfos[i] = $.extend(true, {}, groupingInfoDefaults, groupingInfos[i]); + var gi = groupingInfos[i] = Slick.Utils.extend({}, groupingInfoDefaults, groupingInfos[i]); gi.getterIsAFn = typeof gi.getter === "function"; // pre-compile accumulator loops @@ -1206,7 +1206,7 @@ return; } - var previousPagingInfo = $.extend(true, {}, getPagingInfo()); + var previousPagingInfo = Slick.Utils.extend({}, getPagingInfo()); var countBefore = rows.length; var totalRowsBefore = totalRows; @@ -1427,7 +1427,7 @@ var selectedData = []; var selectedIds = getAllSelectedIds(); selectedIds.forEach(function (id) { - selectedData.push(self.getItemById(id)); + selectedData.push(self.getItemById(id)); }); return selectedData; } @@ -1495,7 +1495,7 @@ this.onRowsOrCountChanged.subscribe(update); } - $.extend(this, { + Slick.Utils.extend(this, { // methods "beginUpdate": beginUpdate, "endUpdate": endUpdate, @@ -1685,18 +1685,16 @@ // TODO: merge common aggregators in one to prevent needles iterating // exports - $.extend(true, window, { - Slick: { - Data: { - DataView: DataView, - Aggregators: { - Avg: AvgAggregator, - Min: MinAggregator, - Max: MaxAggregator, - Sum: SumAggregator, - Count: CountAggregator - } + Slick.Utils.extend(Slick, { + Data: { + DataView: DataView, + Aggregators: { + Avg: AvgAggregator, + Min: MinAggregator, + Max: MaxAggregator, + Sum: SumAggregator, + Count: CountAggregator } } }); -})(jQuery); +})(); diff --git a/slick.editors.js b/slick.editors.js index ca6b404f..17e99cda 100644 --- a/slick.editors.js +++ b/slick.editors.js @@ -4,61 +4,68 @@ * @namespace Slick */ -(function ($) { +(function () { + + const utils = Slick.Utils; + function TextEditor(args) { - var $input; + var input; var defaultValue; var scope = this; + var navOnLR; this.args = args; this.init = function () { - var navOnLR = args.grid.getOptions().editorCellNavOnLRKeys; - $input = $("") - .appendTo(args.container) - .on("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav) - .focus() - .select(); + navOnLR = args.grid.getOptions().editorCellNavOnLRKeys; + input = utils.template("", args.container); + input.addEventListener("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav); + input.focus(); + input.select(); // don't show Save/Cancel when it's a Composite Editor and also trigger a onCompositeEditorChange event when input changes if (args.compositeEditorOptions) { - $input.on("change", function () { - var activeCell = args.grid.getActiveCell(); - - // when valid, we'll also apply the new value to the dataContext item object - if (scope.validate().valid) { - scope.applyValue(scope.args.item, scope.serializeValue()); - } - scope.applyValue(scope.args.compositeEditorOptions.formValues, scope.serializeValue()); - args.grid.onCompositeEditorChange.notify({ row: activeCell.row, cell: activeCell.cell, item: scope.args.item, column: scope.args.column, formValues: scope.args.compositeEditorOptions.formValues }); - }); + input.addEventListener("change", this.onChange); } }; + this.onChange = function() { + var activeCell = args.grid.getActiveCell(); + + // when valid, we'll also apply the new value to the dataContext item object + if (scope.validate().valid) { + scope.applyValue(scope.args.item, scope.serializeValue()); + } + scope.applyValue(scope.args.compositeEditorOptions.formValues, scope.serializeValue()); + args.grid.onCompositeEditorChange.notify({ row: activeCell.row, cell: activeCell.cell, item: scope.args.item, column: scope.args.column, formValues: scope.args.compositeEditorOptions.formValues }); + } + this.destroy = function () { - $input.remove(); + input.removeEventListener("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav); + input.removeEventListener("change", this.onChange) + input.remove(); }; this.focus = function () { - $input.focus(); + input.focus(); }; this.getValue = function () { - return $input.val(); + return input.value; }; this.setValue = function (val) { - $input.val(val); + input.value = val; }; this.loadValue = function (item) { defaultValue = item[args.column.field] || ""; - $input.val(defaultValue); - $input[0].defaultValue = defaultValue; - $input.select(); + input.value = defaultValue; + input.defaultValue = defaultValue; + input.select(); }; this.serializeValue = function () { - return $input.val(); + return input.value; }; this.applyValue = function (item, state) { @@ -66,12 +73,12 @@ }; this.isValueChanged = function () { - return (!($input.val() === "" && defaultValue == null)) && ($input.val() != defaultValue); + return (!(input.value === "" && defaultValue == null)) && (input.value != defaultValue); }; this.validate = function () { if (args.column.validator) { - var validationResults = args.column.validator($input.val(), args); + var validationResults = args.column.validator(input.value, args); if (!validationResults.valid) { return validationResults; } @@ -87,22 +94,21 @@ } function IntegerEditor(args) { - var $input; + var input; var defaultValue; var scope = this; this.args = args; this.init = function () { var navOnLR = args.grid.getOptions().editorCellNavOnLRKeys; - $input = $("") - .appendTo(args.container) - .on("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav) - .focus() - .select(); + input = utils.template("", args.container); + input.addEventListener("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav); + input.focus() + input.select(); // trigger onCompositeEditorChange event when input changes and it's a Composite Editor if (args.compositeEditorOptions) { - $input.on("change", function () { + input.addEventListener("change", function () { var activeCell = args.grid.getActiveCell(); // when valid, we'll also apply the new value to the dataContext item object @@ -116,22 +122,22 @@ }; this.destroy = function () { - $input.remove(); + input.remove(); }; this.focus = function () { - $input.focus(); + input.focus(); }; this.loadValue = function (item) { defaultValue = item[args.column.field]; - $input.val(defaultValue); - $input[0].defaultValue = defaultValue; - $input.select(); + input.value = defaultValue; + input.defaultValue = defaultValue; + input.select(); }; this.serializeValue = function () { - return parseInt($input.val(), 10) || 0; + return parseInt(input.value, 10) || 0; }; this.applyValue = function (item, state) { @@ -139,11 +145,11 @@ }; this.isValueChanged = function () { - return (!($input.val() === "" && defaultValue == null)) && ($input.val() != defaultValue); + return (!(input.value === "" && defaultValue == null)) && (input.value != defaultValue); }; this.validate = function () { - if (isNaN($input.val())) { + if (isNaN(input.value)) { return { valid: false, msg: "Please enter a valid integer" @@ -151,7 +157,7 @@ } if (args.column.validator) { - var validationResults = args.column.validator($input.val(), args); + var validationResults = args.column.validator(input.value, args); if (!validationResults.valid) { return validationResults; } @@ -167,22 +173,21 @@ } function FloatEditor(args) { - var $input; + var input; var defaultValue; var scope = this; this.args = args; this.init = function () { var navOnLR = args.grid.getOptions().editorCellNavOnLRKeys; - $input = $("") - .appendTo(args.container) - .on("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav) - .focus() - .select(); + input = utils.template("", args.container); + input.addEventListener("keydown.nav", navOnLR ? handleKeydownLRNav : handleKeydownLRNoNav); + input.focus() + input.select(); // trigger onCompositeEditorChange event when input changes and it's a Composite Editor if (args.compositeEditorOptions) { - $input.on("change", function () { + input.addEventListener("change", function () { var activeCell = args.grid.getActiveCell(); // when valid, we'll also apply the new value to the dataContext item object @@ -196,11 +201,11 @@ }; this.destroy = function () { - $input.remove(); + input.remove(); }; this.focus = function () { - $input.focus(); + input.focus(); }; function getDecimalPlaces() { @@ -222,13 +227,13 @@ defaultValue = defaultValue.toFixed(decPlaces); } - $input.val(defaultValue); - $input[0].defaultValue = defaultValue; - $input.select(); + input.value = defaultValue; + input.defaultValue = defaultValue; + input.select(); }; this.serializeValue = function () { - var rtn = parseFloat($input.val()); + var rtn = parseFloat(input.value); if (FloatEditor.AllowEmptyValue) { if (!rtn && rtn !== 0) { rtn = ''; } } else { @@ -250,11 +255,11 @@ }; this.isValueChanged = function () { - return (!($input.val() === "" && defaultValue == null)) && ($input.val() != defaultValue); + return (!(input.value === "" && defaultValue == null)) && (input.value != defaultValue); }; this.validate = function () { - if (isNaN($input.val())) { + if (isNaN(input.value)) { return { valid: false, msg: "Please enter a valid number" @@ -262,7 +267,7 @@ } if (args.column.validator) { - var validationResults = args.column.validator($input.val(), args); + var validationResults = args.column.validator(input.value, args); if (!validationResults.valid) { return validationResults; } @@ -280,127 +285,22 @@ FloatEditor.DefaultDecimalPlaces = null; FloatEditor.AllowEmptyValue = false; - function DateEditor(args) { - var $input; - var defaultValue; - var scope = this; - var calendarOpen = false; - this.args = args; - - this.init = function () { - $input = $(""); - $input.appendTo(args.container); - $input.focus().select(); - $input.datepicker({ - showOn: "button", - buttonImageOnly: true, - beforeShow: function () { - calendarOpen = true; - }, - onClose: function () { - calendarOpen = false; - - // trigger onCompositeEditorChange event when input changes and it's a Composite Editor - if (args.compositeEditorOptions) { - var activeCell = args.grid.getActiveCell(); - - // when valid, we'll also apply the new value to the dataContext item object - if (scope.validate().valid) { - scope.applyValue(scope.args.item, scope.serializeValue()); - } - scope.applyValue(scope.args.compositeEditorOptions.formValues, scope.serializeValue()); - args.grid.onCompositeEditorChange.notify({ row: activeCell.row, cell: activeCell.cell, item: scope.args.item, column: scope.args.column, formValues: scope.args.compositeEditorOptions.formValues }); - } - } - }); - - $input.width($input.width() - (!args.compositeEditorOptions ? 18 : 28)); - }; - - this.destroy = function () { - $.datepicker.dpDiv.stop(true, true); - $input.datepicker("hide"); - $input.datepicker("destroy"); - $input.remove(); - }; - - this.show = function () { - if (calendarOpen) { - $.datepicker.dpDiv.stop(true, true).show(); - } - }; - - this.hide = function () { - if (calendarOpen) { - $.datepicker.dpDiv.stop(true, true).hide(); - } - }; - - this.position = function (position) { - if (!calendarOpen) { - return; - } - $.datepicker.dpDiv - .css("top", position.top + 30) - .css("left", position.left); - }; - - this.focus = function () { - $input.focus(); - }; - - this.loadValue = function (item) { - defaultValue = item[args.column.field]; - $input.val(defaultValue); - $input[0].defaultValue = defaultValue; - $input.select(); - }; - - this.serializeValue = function () { - return $input.val(); - }; - - this.applyValue = function (item, state) { - item[args.column.field] = state; - }; - - this.isValueChanged = function () { - return (!($input.val() === "" && defaultValue == null)) && ($input.val() != defaultValue); - }; - - this.validate = function () { - if (args.column.validator) { - var validationResults = args.column.validator($input.val(), args); - if (!validationResults.valid) { - return validationResults; - } - } - - return { - valid: true, - msg: null - }; - }; - - this.init(); - } - function FlatpickrEditor(args) { if (typeof flatpickr === 'undefined') { throw new Error('Flatpickr not loaded but required in SlickGrid.Editors, refer to Flatpickr documentation: https://flatpickr.js.org/getting-started/'); } - var $input; + var input; var defaultValue; var scope = this; this.args = args; var flatpickrInstance; this.init = function () { - $input = $(''); - $input.appendTo(args.container); - $input.focus().select(); - flatpickrInstance = $input.flatpickr({ + input = utils.template('', args.container); + input.focus(); + input.select(); + flatpickrInstance = flatpickr(input, { closeOnSelect: true, allowInput: true, altInput: true, @@ -428,13 +328,13 @@ }, 50); } - $input.width($input.width() - (!args.compositeEditorOptions ? 18 : 28)); + utils.width(input, utils.width(input) - (!args.compositeEditorOptions ? 18 : 28)); }; this.destroy = function () { scope.hide(); flatpickrInstance.destroy(); - $input.remove(); + input.remove(); }; this.show = function () { @@ -450,19 +350,19 @@ }; this.focus = function () { - $input.focus(); + input.focus(); }; this.loadValue = function (item) { defaultValue = item[args.column.field]; - $input.val(defaultValue); - $input[0].defaultValue = defaultValue; - $input.select(); + input.value = defaultValue; + input.defaultValue = defaultValue; + input.select(); flatpickrInstance.setDate(defaultValue); }; this.serializeValue = function () { - return $input.val(); + return input.value; }; this.applyValue = function (item, state) { @@ -470,12 +370,12 @@ }; this.isValueChanged = function () { - return (!($input.val() === "" && defaultValue == null)) && ($input.val() != defaultValue); + return (!(input.value === "" && defaultValue == null)) && (input.value != defaultValue); }; this.validate = function () { if (args.column.validator) { - var validationResults = args.column.validator($input.val(), args); + var validationResults = args.column.validator(input.value, args); if (!validationResults.valid) { return validationResults; } @@ -491,19 +391,18 @@ } function YesNoSelectEditor(args) { - var $select; + var select; var defaultValue; var scope = this; this.args = args; this.init = function () { - $select = $(""); - $select.appendTo(args.container); - $select.focus(); + select = utils.template("", args.container); + select.focus(); // trigger onCompositeEditorChange event when input changes and it's a Composite Editor if (args.compositeEditorOptions) { - $select.on("change", function () { + select.addEventListener("change", function () { var activeCell = args.grid.getActiveCell(); // when valid, we'll also apply the new value to the dataContext item object @@ -517,20 +416,20 @@ }; this.destroy = function () { - $select.remove(); + select.remove(); }; this.focus = function () { - $select.focus(); + select.focus(); }; this.loadValue = function (item) { - $select.val((defaultValue = item[args.column.field]) ? "yes" : "no"); - $select.select(); + select.value = ((defaultValue = item[args.column.field]) ? "yes" : "no"); + select.select(); }; this.serializeValue = function () { - return ($select.val() == "yes"); + return select.value == "yes"; }; this.applyValue = function (item, state) { @@ -538,7 +437,7 @@ }; this.isValueChanged = function () { - return ($select.val() != defaultValue); + return select.value != defaultValue; }; this.validate = function () { @@ -552,19 +451,18 @@ } function CheckboxEditor(args) { - var $select; + var select; var defaultValue; var scope = this; this.args = args; this.init = function () { - $select = $(""); - $select.appendTo(args.container); - $select.focus(); + select = utils.template("", args.container); + select.focus(); // trigger onCompositeEditorChange event when input checkbox changes and it's a Composite Editor if (args.compositeEditorOptions) { - $select.on("change", function () { + select.addEventListener("change", function () { var activeCell = args.grid.getActiveCell(); // when valid, we'll also apply the new value to the dataContext item object @@ -578,28 +476,24 @@ }; this.destroy = function () { - $select.remove(); + select.remove(); }; this.focus = function () { - $select.focus(); + select.focus(); }; this.loadValue = function (item) { defaultValue = !!item[args.column.field]; if (defaultValue) { - $select.prop('checked', true); + select.checked = true; } else { - $select.prop('checked', false); + select.checked = false; } }; - this.preClick = function () { - $select.prop('checked', !$select.prop('checked')); - }; - this.serializeValue = function () { - return $select.prop('checked'); + return select.checked; }; this.applyValue = function (item, state) { @@ -621,13 +515,13 @@ } function PercentCompleteEditor(args) { - var $input, $picker; + var input, picker; var defaultValue; var scope = this; this.args = args; - var $slider; + var slider; var sliderInputHandler = function () { - $input.val(this.value); + input.value = this.value; } var sliderChangeHandler = function () { // trigger onCompositeEditorChange event when slider stops and it's a Composite Editor @@ -644,47 +538,49 @@ } this.init = function () { - $input = $(''); - $input.width($(args.container).innerWidth() - 25); - $input.appendTo(args.container); + input = utils.template('', args.container); + utils.width(input, args.container.clientWidth - 25); - $picker = $("
").appendTo(args.container); - $picker.append("
"); - $picker.find(".editor-percentcomplete-buttons").append('

'); - $input.focus().select(); + picker = utils.template("
", args.container); + utils.template("


", picker); + input.focus(); + input.select(); - $slider = $picker.find('input.editor-percentcomplete-slider'); - $slider.val(defaultValue); + slider = picker.querySelector('input.editor-percentcomplete-slider'); + slider.value = defaultValue; - $slider.on('input', sliderInputHandler); - $slider.on('change', sliderChangeHandler); + slider.addEventListener('input', sliderInputHandler); + slider.addEventListener('change', sliderChangeHandler); - $picker.find(".editor-percentcomplete-buttons button").on("click", function (e) { - $input.val($(this).attr("val")); - $slider.val($(this).attr("val")); + const buttons = picker.querySelectorAll(".editor-percentcomplete-buttons button"); + [].forEach.call(buttons, (button) => { + button.addEventListener("click", function (e) { + input.value = this.getAttribute("val"); + slider.value = this.getAttribute("val"); + }); }); }; this.destroy = function () { - $slider.off('input', sliderInputHandler); - $slider.off('change', sliderChangeHandler); - $input.remove(); - $picker.remove(); + slider.removeEventListener('input', sliderInputHandler); + slider.removeEventListener('change', sliderChangeHandler); + input.remove(); + picker.remove(); }; this.focus = function () { - $input.focus(); + input.focus(); }; this.loadValue = function (item) { defaultValue = item[args.column.field]; - $slider.val(defaultValue); - $input.val(defaultValue); - $input.select(); + slider.value = defaultValue; + input.value = defaultValue; + input.select(); }; this.serializeValue = function () { - return parseInt($input.val(), 10) || 0; + return parseInt(input.value, 10) || 0; }; this.applyValue = function (item, state) { @@ -692,11 +588,11 @@ }; this.isValueChanged = function () { - return (!($input.val() === "" && defaultValue == null)) && ((parseInt($input.val(), 10) || 0) != defaultValue); + return (!(input.value === "" && defaultValue == null)) && ((parseInt(input.value, 10) || 0) != defaultValue); }; this.validate = function () { - if (isNaN(parseInt($input.val(), 10))) { + if (isNaN(parseInt(input.value, 10))) { return { valid: false, msg: "Please enter a valid positive number" @@ -718,7 +614,7 @@ * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter. */ function LongTextEditor(args) { - var $input, $wrapper; + var input, wrapper; var defaultValue; var scope = this; this.args = args; @@ -726,22 +622,22 @@ this.init = function () { var compositeEditorOptions = args.compositeEditorOptions; var navOnLR = args.grid.getOptions().editorCellNavOnLRKeys; - var $container = compositeEditorOptions ? args.container : $('body'); + var container = compositeEditorOptions ? args.container : document.body; - $wrapper = $("
") - .appendTo($container); + wrapper = utils.template("
", container); if (compositeEditorOptions) { - $wrapper.css({ position: 'relative', padding: 0, border: 0 }); + wrapper.style.position = 'relative'; + utils.setStyleSize(wrapper, "padding", 0); + utils.setStyleSize(wrapper, "border", 0); } else { - $wrapper.css({ position: 'absolute' }); + wrapper.style.position = 'absolute'; } - $input = $("