From 80a420020035588480783927268f619cf73c4edd Mon Sep 17 00:00:00 2001 From: Radoslav Karaivanov Date: Tue, 2 Jul 2019 19:26:02 +0300 Subject: [PATCH 1/7] feat(igx-grid): Copy into clipboard behavior Closes #4907 --- .../src/lib/core/grid-selection.ts | 9 - .../src/lib/grids/grid-base.component.ts | 64 ++- src/app/app.component.ts | 5 + src/app/app.module.ts | 7 +- .../grid-clipboard/grid-clipboard.sample.html | 36 ++ .../grid-clipboard/grid-clipboard.sample.ts | 21 + .../grid-column-moving.sample.ts | 437 +----------------- src/app/routing.ts | 5 + src/app/shared/sample-data.ts | 434 +++++++++++++++++ 9 files changed, 571 insertions(+), 447 deletions(-) create mode 100644 src/app/grid-clipboard/grid-clipboard.sample.html create mode 100644 src/app/grid-clipboard/grid-clipboard.sample.ts create mode 100644 src/app/shared/sample-data.ts diff --git a/projects/igniteui-angular/src/lib/core/grid-selection.ts b/projects/igniteui-angular/src/lib/core/grid-selection.ts index bb7837bc50f..910b09ca0c7 100644 --- a/projects/igniteui-angular/src/lib/core/grid-selection.ts +++ b/projects/igniteui-angular/src/lib/core/grid-selection.ts @@ -524,13 +524,4 @@ export class IgxGridSelectionService { selection.addRange(this._selectionRange || document.createRange()); } } - - _moveSelectionChrome(node: Node) { - const selection = window.getSelection(); - selection.removeAllRanges(); - const range = new Range(); - range.selectNode(node); - range.collapse(true); - selection.addRange(range); - } } diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index a6ea22b37f4..0e559e38216 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -23,12 +23,13 @@ import { ViewChildren, ViewContainerRef, InjectionToken, - Optional + Optional, + HostListener } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil, first, filter } from 'rxjs/operators'; import { IgxSelectionAPIService } from '../core/selection'; -import { cloneArray, isEdge, isNavigationKey, CancelableEventArgs, flatten, mergeObjects } from '../core/utils'; +import { cloneArray, isEdge, isNavigationKey, CancelableEventArgs, flatten, mergeObjects, isIE } from '../core/utils'; import { DataType } from '../data-operations/data-util'; import { FilteringLogic, IFilteringExpression } from '../data-operations/filtering-expression.interface'; import { IGroupByRecord } from '../data-operations/groupby-record.interface'; @@ -89,6 +90,7 @@ import { IgxGridFilteringRowComponent } from './filtering/grid-filtering-row.com import { IgxDragIndicatorIconDirective } from './row-drag.directive'; import { IgxDragDirective } from '../directives/dragdrop/dragdrop.directive'; import { DeprecateProperty } from '../core/deprecateDecorators'; +import { CharSeparatedValueData } from '../services/csv/char-separated-value-data'; const MINIMUM_COLUMN_WIDTH = 136; const FILTER_ROW_HEIGHT = 50; @@ -102,6 +104,12 @@ const MIN_ROW_EDITING_COUNT_THRESHOLD = 2; export const IgxGridTransaction = new InjectionToken('IgxGridTransaction'); +export interface IGridClipboardEvent { + type: string; + data: any[]; + cancel: boolean; +} + export interface IGridCellEventArgs { cell: IgxGridCellComponent; event: Event; @@ -1534,6 +1542,12 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements @Output() public onRowDragEnd = new EventEmitter(); + /** + * TODO: Write doc + */ + @Output() + onGridCopy = new EventEmitter(); + /** * @hidden */ @@ -2355,6 +2369,16 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements } } + /** + * TODO: Write doc + */ + @Input() + clipboardOptions = { + enabled: true, + copyHeaders: true, + separator: '\t' + }; + /** * @hidden */ @@ -2619,6 +2643,9 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements private keydownHandler(event) { const key = event.key.toLowerCase(); + if (event.ctrlKey && key === 'c' && this.clipboardOptions.enabled) { + isIE() ? this.copyHandler(null, true) : this.document.execCommand('copy'); + } if ((isNavigationKey(key) && event.keyCode !== 32) || key === 'tab' || key === 'pagedown' || key === 'pageup') { event.preventDefault(); if (key === 'pagedown') { @@ -4888,6 +4915,39 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements event.target.scrollTop = 0; } + /** + * @hidden + * @internal + */ + @HostListener('copy', ['$event']) + public copyHandler(event, ie11 = false) { + if (!this.clipboardOptions.enabled) { + return; + } + const data = this.getSelectedData(); + const ev = { type: 'copy', data, cancel: false } as IGridClipboardEvent; + this.onGridCopy.emit(ev); + + if (ev.cancel) { + return; + } + + const transformer = new CharSeparatedValueData(ev.data, this.clipboardOptions.separator); + let result = transformer.prepareData(); + + if (!this.clipboardOptions.copyHeaders) { + result = result.substring(result.indexOf('\n') + 1); + } + + if (ie11) { + (window as any).clipboardData.setData('Text', result); + return; + } + + event.preventDefault(); + event.clipboardData.setData('text/plain', result); + } + /** * This method allows you to navigate to a position * in the grid based on provided `rowindex` and `visibleColumnIndex`, diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 69ee6b70900..c0a2c506441 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -138,6 +138,11 @@ export class AppComponent implements OnInit { icon: 'view_column', name: 'Grid Cell Editing' }, + { + link: '/gridClipboard', + icon: 'insert_comment', + name: 'Grid Clipboard Interaction' + }, { link: '/gridColumnGroups', icon: 'view_column', diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 83b322e8d98..73816e32775 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -5,7 +5,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NgModule } from '@angular/core'; import { IgxIconModule, IgxGridModule, IgxExcelExporterService, IgxCsvExporterService, IgxOverlayService, - IgxGridTransaction, IgxTransactionService, IgxTreeGridModule, IgxHierarchicalGridModule, IgxInputGroupModule} from 'igniteui-angular'; + IgxGridTransaction, IgxTransactionService, IgxTreeGridModule, IgxHierarchicalGridModule, IgxInputGroupModule, IgxIconService} from 'igniteui-angular'; import { IgxColumnHidingModule } from 'igniteui-angular'; import { SharedModule } from './shared/shared.module'; import { IgxDragDropModule } from '../../projects/igniteui-angular/src/lib/directives/dragdrop/dragdrop.directive'; @@ -95,6 +95,7 @@ import { TreeGridLoadOnDemandSampleComponent } from './tree-grid-load-on-demand/ import { GridFilterTemplateSampleComponent } from './grid-filter-template/grid-filter-template.sample'; import { GridMRLConfigSampleComponent } from './grid-multi-row-layout-config/grid-mrl-config.sample'; import { GridMRLCustomNavigationSampleComponent } from './grid-mrl-custom-navigation/grid-mrl-custom-navigation'; +import { GridClipboardSampleComponent } from './grid-clipboard/grid-clipboard.sample'; @@ -184,7 +185,8 @@ const components = [ CalendarViewsSampleComponent, GridSearchBoxComponent, GridSearchComponent, - GridFilterTemplateSampleComponent + GridFilterTemplateSampleComponent, + GridClipboardSampleComponent ]; @NgModule({ @@ -210,6 +212,7 @@ const components = [ LocalService, RemoteService, IgxExcelExporterService, + IgxIconService, IgxCsvExporterService, IgxOverlayService, { provide: DisplayDensityToken, useFactory: () => ({ displayDensity: DisplayDensity.comfortable }) } diff --git a/src/app/grid-clipboard/grid-clipboard.sample.html b/src/app/grid-clipboard/grid-clipboard.sample.html new file mode 100644 index 00000000000..5a5ebd35acb --- /dev/null +++ b/src/app/grid-clipboard/grid-clipboard.sample.html @@ -0,0 +1,36 @@ +
+ + +
+
+
+ + + + clear + + The default value is a single tabulation which of course is shown as whitespace above. + Click the clear icon to reset it back to tabulation. + + +
+ Toggle grid copy behavior + Toggle copying of header labels + +
+
+ + +
+ +
+ +
+ + + + +
+
+
+
diff --git a/src/app/grid-clipboard/grid-clipboard.sample.ts b/src/app/grid-clipboard/grid-clipboard.sample.ts new file mode 100644 index 00000000000..db98204c1b1 --- /dev/null +++ b/src/app/grid-clipboard/grid-clipboard.sample.ts @@ -0,0 +1,21 @@ +import { Component } from '@angular/core'; +import { SAMPLE_DATA } from '../shared/sample-data'; + +@Component({ + selector: 'app-grid-clipboard-sample', + templateUrl: './grid-clipboard.sample.html' +}) +export class GridClipboardSampleComponent { + + data: any[]; + + options = { + enabled: true, + copyHeaders: true, + separator: '\t' + }; + + constructor() { + this.data = SAMPLE_DATA.slice(0); + } +} diff --git a/src/app/grid-column-moving/grid-column-moving.sample.ts b/src/app/grid-column-moving/grid-column-moving.sample.ts index f91eb503a85..bdf60db9e09 100644 --- a/src/app/grid-column-moving/grid-column-moving.sample.ts +++ b/src/app/grid-column-moving/grid-column-moving.sample.ts @@ -1,5 +1,6 @@ import { Component, ViewChild, OnInit } from '@angular/core'; import { IgxGridComponent } from 'igniteui-angular'; +import { SAMPLE_DATA } from '../shared/sample-data'; @Component({ providers: [], @@ -28,6 +29,8 @@ export class GridColumnMovingSampleComponent implements OnInit { { label: 'compact', selected: this.density === 'compact', togglable: true } ]; + this.data = SAMPLE_DATA.slice(0); + this.columns = [ { field: 'ID', width: 150, resizable: true, movable: true, sortable: false, filterable: true, groupable: true, summary: true, type: 'string' }, { field: 'CompanyName', width: 150, resizable: true, movable: true, sortable: true, filterable: true, groupable: true, summary: true, type: 'string'}, @@ -43,440 +46,6 @@ export class GridColumnMovingSampleComponent implements OnInit { { field: 'DateCreated', width: 150, resizable: true, movable: true, sortable: true, filterable: true, groupable: true, summary: false, type: 'date' }, { field: 'Contract', width: 150, resizable: true, movable: true, sortable: true, filterable: true, groupable: true, summary: true, type: 'boolean' } ]; - this.data = [ - { - 'ID': 'ALFKI', - 'CompanyName': 'Alfreds Futterkiste', - 'ContactName': 'Maria Anders', - 'ContactTitle': 'Sales Representative', - 'Address': 'Obere Str. 57', - 'City': 'Berlin', 'Region': undefined, - 'PostalCode': '12209', - 'Country': 'Germany', - 'Phone': '030-0074321', - 'Fax': '030-0076545', - 'Employees': 68, - 'DateCreated': new Date(2018, 8, 17), - 'Contract': null - }, - { - 'ID': 'ANATR', - 'CompanyName': 'Ana Trujillo Emparedados y helados', - 'ContactName': 'Ana Trujillo', - 'ContactTitle': 'Owner', - 'Address': 'Avda. de la Constitución 2222', - 'City': 'México D.F.', - 'Region': '', - 'PostalCode': '05021', - 'Country': 'Mexico', - 'Phone': '(5) 555-4729', - 'Fax': '(5) 555-3745', - 'Employees': 47, - 'DateCreated': new Date(2015, 10, 1), - 'Contract': true - }, - { - 'ID': 'ANTON', - 'CompanyName': 'Antonio Moreno Taquería', - 'ContactName': 'Antonio Moreno', - 'ContactTitle': 'Owner', - 'Address': 'Mataderos 2312', - 'City': 'México D.F.', - 'Region': null, - 'PostalCode': '05023', - 'Country': 'Mexico', - 'Phone': '(5) 555-3932', - 'Fax': null, - 'Employees': 16, - 'DateCreated': new Date(2016, 5, 5), - 'Contract': false - }, - { - 'ID': 'AROUT', - 'CompanyName': 'Around the Horn', - 'ContactName': 'Thomas Hardy', - 'ContactTitle': 'Sales Representative', - 'Address': '120 Hanover Sq.', - 'City': 'London', - 'Region': null, - 'PostalCode': 'WA1 1DP', - 'Country': 'UK', - 'Phone': '(171) 555-7788', - 'Fax': '(171) 555-6750', - 'Employees': 71, - 'DateCreated': new Date(2010, 2, 15), - 'Contract': false - }, - { - 'ID': 'BERGS', - 'CompanyName': 'Berglunds snabbköp', - 'ContactName': 'Christina Berglund', - 'ContactTitle': 'Order Administrator', - 'Address': 'Berguvsvägen 8', - 'City': 'Luleå', - 'Region': null, - 'PostalCode': 'S-958 22', - 'Country': 'Sweden', - 'Phone': '0921-12 34 65', - 'Fax': '0921-12 34 67', - 'Employees': 213, - 'DateCreated': new Date(2015, 2, 5), - 'Contract': true - }, - { - 'ID': 'BLAUS', - 'CompanyName': 'Blauer See Delikatessen', - 'ContactName': 'Hanna Moos', - 'ContactTitle': 'Sales Representative', - 'Address': 'Forsterstr. 57', - 'City': 'Mannheim', - 'Region': null, - 'PostalCode': '68306', - 'Country': 'Germany', - 'Phone': '0621-08460', - 'Fax': '0621-08924', - 'Employees': 347, - 'DateCreated': new Date(2016, 7, 1), - 'Contract': true - }, - { - 'ID': 'BLONP', - 'CompanyName': 'Blondesddsl père et fils', - 'ContactName': 'Frédérique Citeaux', - 'ContactTitle': 'Marketing Manager', - 'Address': '24, place Kléber', - 'City': 'Strasbourg', - 'Region': null, - 'PostalCode': '67000', - 'Country': 'France', - 'Phone': '88.60.15.31', - 'Fax': '88.60.15.32', - 'Employees': 34, - 'DateCreated': new Date(2016, 10, 5), - 'Contract': true - }, - { - 'ID': 'BOLID', - 'CompanyName': 'Bólido Comidas preparadas', - 'ContactName': 'Martín Sommer', - 'ContactTitle': 'Owner', - 'Address': 'C/ Araquil, 67', - 'City': 'Madrid', - 'Region': null, - 'PostalCode': '28023', - 'Country': 'Spain', - 'Phone': '(91) 555 22 82', - 'Fax': '(91) 555 91 99', - 'Employees': 54, - 'DateCreated': new Date(2016, 4, 20), - 'Contract': true - }, - { - 'ID': 'BONAP', - 'CompanyName': 'Bon app', - 'ContactName': 'Laurence Lebihan', - 'ContactTitle': 'Owner', - 'Address': '12, rue des Bouchers', - 'City': 'Marseille', - 'Region': null, - 'PostalCode': '13008', - 'Country': 'France', - 'Phone': '91.24.45.40', - 'Fax': '91.24.45.41', - 'Employees': 68, - 'DateCreated': new Date(2018, 3, 5), - 'Contract': false - }, - { - 'ID': 'BOTTM', - 'CompanyName': 'Bottom-Dollar Markets', - 'ContactName': 'Elizabeth Lincoln', - 'ContactTitle': 'Accounting Manager', - 'Address': '23 Tsawassen Blvd.', - 'City': 'Tsawassen', - 'Region': 'BC', - 'PostalCode': 'T2F 8M4', - 'Country': 'Canada', - 'Phone': '(604) 555-4729', - 'Fax': '(604) 555-3745', - 'Employees': 107, - 'DateCreated': new Date(2017, 6, 10), - 'Contract': true - }, - { - 'ID': 'BSBEV', - 'CompanyName': 'Beverages', - 'ContactName': 'Victoria Ashworth', - 'ContactTitle': 'Sales Representative', - 'Address': 'Fauntleroy Circus', - 'City': 'London', - 'Region': null, - 'PostalCode': 'EC2 5NT', - 'Country': 'UK', - 'Phone': '(171) 555-1212', - 'Fax': null, - 'Employees': 197, - 'DateCreated': new Date(2017, 10, 4), - 'Contract': true - }, - { - 'ID': 'CACTU', - 'CompanyName': - 'Cactus Comidas para llevar', - 'ContactName': 'Patricio Simpson', - 'ContactTitle': 'Sales Agent', - 'Address': 'Cerrito 333', - 'City': 'Buenos Aires', - 'Region': null, - 'PostalCode': '1010', - 'Country': 'Argentina', - 'Phone': '(1) 135-5555', - 'Fax': '(1) 135-4892', - 'Employees': 33, - 'DateCreated': new Date(2014, 5, 12), - 'Contract': false - }, - { - 'ID': 'CENTC', - 'CompanyName': 'Centro comercial Moctezuma', - 'ContactName': 'Francisco Chang', - 'ContactTitle': 'Marketing Manager', - 'Address': 'Sierras de Granada 9993', - 'City': 'México D.F.', - 'Region': null, - 'PostalCode': '05022', - 'Country': 'Mexico', - 'Phone': '(5) 555-3392', - 'Fax': '(5) 555-7293', - 'Employees': 18, - 'DateCreated': new Date(2015, 6, 27), - 'Contract': true - }, - { - 'ID': 'CHOPS', - 'CompanyName': 'Chop-suey Chinese', - 'ContactName': 'Yang Wang', - 'ContactTitle': 'Owner', - 'Address': 'Hauptstr. 29', - 'City': 'Bern', - 'Region': null, - 'PostalCode': '3012', - 'Country': 'Switzerland', - 'Phone': '0452-076545', - 'Fax': null, - 'Employees': 380, - 'DateCreated': new Date(2011, 8, 6), - 'Contract': true - }, - { - 'ID': 'COMMI', - 'CompanyName': 'Comércio Mineiro', - 'ContactName': 'Pedro Afonso', - 'ContactTitle': 'Sales Associate', - 'Address': 'Av. dos Lusíadas, 23', - 'City': 'Sao Paulo', 'Region': 'SP', - 'PostalCode': '05432-043', - 'Country': 'Brazil', - 'Phone': '(11) 555-7647', - 'Fax': null, - 'Employees': 137, - 'DateCreated': new Date(2012, 6, 10), - 'Contract': false - }, - { - 'ID': 'CONSH', - 'CompanyName': 'Consolidated Holdings', - 'ContactName': 'Elizabeth Brown', - 'ContactTitle': 'Sales Representative', - 'Address': 'Berkeley Gardens 12 Brewery', - 'City': 'London', - 'Region': null, - 'PostalCode': 'WX1 6LT', - 'Country': 'UK', - 'Phone': '(171) 555-2282', - 'Fax': '(171) 555-9199', - 'Employees': 150, - 'DateCreated': new Date(2012, 6, 10), - 'Contract': false - }, - { - 'ID': 'DRACD', - 'CompanyName': 'Drachenblut Delikatessen', - 'ContactName': 'Sven Ottlieb', - 'ContactTitle': 'Order Administrator', - 'Address': 'Walserweg 21', - 'City': 'Aachen', - 'Region': null, - 'PostalCode': '52066', - 'Country': 'Germany', - 'Phone': '0241-039123', - 'Fax': '0241-059428', - 'Employees': 265, - 'DateCreated': new Date(2014, 9, 11), - 'Contract': true - }, - { - 'ID': 'DUMON', - 'CompanyName': 'Du monde entier', - 'ContactName': 'Janine Labrune', - 'ContactTitle': 'Owner', - 'Address': '67, rue des Cinquante Otages', - 'City': 'Nantes', - 'Region': null, - 'PostalCode': '44000', - 'Country': 'France', - 'Phone': '40.67.88.88', - 'Fax': '40.67.89.89', - 'Employees': 24, - 'DateCreated': new Date(2015, 8, 4), - 'Contract': true - }, - { - 'ID': 'EASTC', - 'CompanyName': 'Eastern Connection', - 'ContactName': 'Ann Devon', - 'ContactTitle': 'Sales Agent', - 'Address': '35 King George', - 'City': 'London', - 'Region': null, - 'PostalCode': 'WX3 6FW', - 'Country': 'UK', - 'Phone': '(171) 555-0297', - 'Fax': '(171) 555-3373', - 'Employees': 123, - 'DateCreated': new Date(2013, 4, 18), - 'Contract': false - }, - { - 'ID': 'ERNSH', - 'CompanyName': - 'Ernst Handel', - 'ContactName': 'Roland Mendel', - 'ContactTitle': 'Sales Manager', - 'Address': 'Kirchgasse 6', - 'City': 'Graz', - 'Region': null, - 'PostalCode': '8010', - 'Country': 'Austria', - 'Phone': '7675-3425', - 'Fax': '7675-3426', - 'Employees': 9, - 'DateCreated': new Date(2013, 7, 9), - 'Contract': true - }, - { - 'ID': 'FAMIA', - 'CompanyName': 'Familia Arquibaldo', - 'ContactName': 'Aria Cruz', - 'ContactTitle': 'Marketing Assistant', - 'Address': 'Rua Orós, 92', - 'City': 'Sao Paulo', - 'Region': 'SP', - 'PostalCode': '05442-030', - 'Country': 'Brazil', - 'Phone': '(11) 555-9857', - 'Fax': null, - 'Employees': 67, - 'DateCreated': new Date(2015, 6, 17), - 'Contract': true - }, - { - 'ID': 'FISSA', - 'CompanyName': 'FISSA Fabrica Inter. Salchichas S.A.', - 'ContactName': 'Diego Roel', - 'ContactTitle': 'Accounting Manager', - 'Address': 'C/ Moralzarzal, 86', - 'City': 'Madrid', - 'Region': null, - 'PostalCode': '28034', - 'Country': 'Spain', - 'Phone': '(91) 555 94 44', - 'Fax': '(91) 555 55 93', - 'Employees': 87, - 'DateCreated': new Date(2017, 3, 15), - 'Contract': false - }, - { - 'ID': 'FOLIG', - 'CompanyName': 'Folies gourmandes', - 'ContactName': 'Martine Rancé', - 'ContactTitle': 'Assistant Sales Agent', - 'Address': '184, chaussée de Tournai', - 'City': 'Lille', - 'Region': null, - 'PostalCode': '59000', - 'Country': 'France', - 'Phone': '20.16.10.16', - 'Fax': '20.16.10.17', - 'Employees': 37, - 'DateCreated': new Date(2014, 5, 14), - 'Contract': false - }, - { - 'ID': 'FOLKO', - 'CompanyName': 'Folk och fä HB', - 'ContactName': 'Maria Larsson', - 'ContactTitle': 'Owner', - 'Address': 'Åkergatan 24', - 'City': 'Bräcke', - 'Region': null, - 'PostalCode': 'S-844 67', - 'Country': 'Sweden', - 'Phone': '0695-34 67 21', - 'Fax': null, - 'Employees': 42, - 'DateCreated': new Date(2011, 3, 21), - 'Contract': true - }, - { - 'ID': 'FRANK', - 'CompanyName': 'Frankenversand', - 'ContactName': 'Peter Franken', - 'ContactTitle': 'Marketing Manager', - 'Address': 'Berliner Platz 43', - 'City': 'München', - 'Region': null, - 'PostalCode': '80805', - 'Country': 'Germany', - 'Phone': '089-0877310', - 'Fax': '089-0877451', - 'Employees': 17, - 'DateCreated': new Date(2010, 7, 24), - 'Contract': true - }, - { - 'ID': 'FRANR', - 'CompanyName': 'France restauration', - 'ContactName': 'Carine Schmitt', - 'ContactTitle': 'Marketing Manager', - 'Address': '54, rue Royale', - 'City': 'Nantes', - 'Region': null, - 'PostalCode': '44000', - 'Country': 'France', - 'Phone': '40.32.21.21', - 'Fax': '40.32.21.20', - 'Employees': 20, - 'DateCreated': new Date(2011, 7, 14), - 'Contract': true - }, - { - 'ID': 'FRANS', - 'CompanyName': 'Franchi S.p.A.', - 'ContactName': 'Paolo Accorti', - 'ContactTitle': 'Sales Representative', - 'Address': 'Via Monte Bianco 34', - 'City': 'Torino', 'Region': null, - 'PostalCode': '10100', - 'Country': 'Italy', - 'Phone': '011-4988260', - 'Fax': '011-4988261', - 'Employees': 5, - 'DateCreated': new Date(2012, 8, 3), - 'Contract': false - } - ]; - // this.data = [...this.data, ...this.data, ...this.data]; } public selectDensity(event) { diff --git a/src/app/routing.ts b/src/app/routing.ts index 8f11165c1c1..aee5b6f8c3f 100644 --- a/src/app/routing.ts +++ b/src/app/routing.ts @@ -73,6 +73,7 @@ import { TreeGridLoadOnDemandSampleComponent } from './tree-grid-load-on-demand/ import { GridFilterTemplateSampleComponent } from './grid-filter-template/grid-filter-template.sample'; import { GridMRLConfigSampleComponent } from './grid-multi-row-layout-config/grid-mrl-config.sample'; import { GridMRLCustomNavigationSampleComponent } from './grid-mrl-custom-navigation/grid-mrl-custom-navigation'; +import { GridClipboardSampleComponent } from './grid-clipboard/grid-clipboard.sample'; const appRoutes = [ { @@ -280,6 +281,10 @@ const appRoutes = [ path: 'gridFilterTemplate', component: GridFilterTemplateSampleComponent }, + { + path: 'gridClipboard', + component: GridClipboardSampleComponent + }, { path: 'gridColumnMoving', component: GridColumnMovingSampleComponent diff --git a/src/app/shared/sample-data.ts b/src/app/shared/sample-data.ts new file mode 100644 index 00000000000..7d6cdc25f3a --- /dev/null +++ b/src/app/shared/sample-data.ts @@ -0,0 +1,434 @@ + +export const SAMPLE_DATA = [ + { + 'ID': 'ALFKI', + 'CompanyName': 'Alfreds Futterkiste', + 'ContactName': 'Maria Anders', + 'ContactTitle': 'Sales Representative', + 'Address': 'Obere Str. 57', + 'City': 'Berlin', 'Region': undefined, + 'PostalCode': '12209', + 'Country': 'Germany', + 'Phone': '030-0074321', + 'Fax': '030-0076545', + 'Employees': 68, + 'DateCreated': new Date(2018, 8, 17), + 'Contract': null + }, + { + 'ID': 'ANATR', + 'CompanyName': 'Ana Trujillo Emparedados y helados', + 'ContactName': 'Ana Trujillo', + 'ContactTitle': 'Owner', + 'Address': 'Avda. de la Constitución 2222', + 'City': 'México D.F.', + 'Region': '', + 'PostalCode': '05021', + 'Country': 'Mexico', + 'Phone': '(5) 555-4729', + 'Fax': '(5) 555-3745', + 'Employees': 47, + 'DateCreated': new Date(2015, 10, 1), + 'Contract': true + }, + { + 'ID': 'ANTON', + 'CompanyName': 'Antonio Moreno Taquería', + 'ContactName': 'Antonio Moreno', + 'ContactTitle': 'Owner', + 'Address': 'Mataderos 2312', + 'City': 'México D.F.', + 'Region': null, + 'PostalCode': '05023', + 'Country': 'Mexico', + 'Phone': '(5) 555-3932', + 'Fax': null, + 'Employees': 16, + 'DateCreated': new Date(2016, 5, 5), + 'Contract': false + }, + { + 'ID': 'AROUT', + 'CompanyName': 'Around the Horn', + 'ContactName': 'Thomas Hardy', + 'ContactTitle': 'Sales Representative', + 'Address': '120 Hanover Sq.', + 'City': 'London', + 'Region': null, + 'PostalCode': 'WA1 1DP', + 'Country': 'UK', + 'Phone': '(171) 555-7788', + 'Fax': '(171) 555-6750', + 'Employees': 71, + 'DateCreated': new Date(2010, 2, 15), + 'Contract': false + }, + { + 'ID': 'BERGS', + 'CompanyName': 'Berglunds snabbköp', + 'ContactName': 'Christina Berglund', + 'ContactTitle': 'Order Administrator', + 'Address': 'Berguvsvägen 8', + 'City': 'Luleå', + 'Region': null, + 'PostalCode': 'S-958 22', + 'Country': 'Sweden', + 'Phone': '0921-12 34 65', + 'Fax': '0921-12 34 67', + 'Employees': 213, + 'DateCreated': new Date(2015, 2, 5), + 'Contract': true + }, + { + 'ID': 'BLAUS', + 'CompanyName': 'Blauer See Delikatessen', + 'ContactName': 'Hanna Moos', + 'ContactTitle': 'Sales Representative', + 'Address': 'Forsterstr. 57', + 'City': 'Mannheim', + 'Region': null, + 'PostalCode': '68306', + 'Country': 'Germany', + 'Phone': '0621-08460', + 'Fax': '0621-08924', + 'Employees': 347, + 'DateCreated': new Date(2016, 7, 1), + 'Contract': true + }, + { + 'ID': 'BLONP', + 'CompanyName': 'Blondesddsl père et fils', + 'ContactName': 'Frédérique Citeaux', + 'ContactTitle': 'Marketing Manager', + 'Address': '24, place Kléber', + 'City': 'Strasbourg', + 'Region': null, + 'PostalCode': '67000', + 'Country': 'France', + 'Phone': '88.60.15.31', + 'Fax': '88.60.15.32', + 'Employees': 34, + 'DateCreated': new Date(2016, 10, 5), + 'Contract': true + }, + { + 'ID': 'BOLID', + 'CompanyName': 'Bólido Comidas preparadas', + 'ContactName': 'Martín Sommer', + 'ContactTitle': 'Owner', + 'Address': 'C/ Araquil, 67', + 'City': 'Madrid', + 'Region': null, + 'PostalCode': '28023', + 'Country': 'Spain', + 'Phone': '(91) 555 22 82', + 'Fax': '(91) 555 91 99', + 'Employees': 54, + 'DateCreated': new Date(2016, 4, 20), + 'Contract': true + }, + { + 'ID': 'BONAP', + 'CompanyName': 'Bon app', + 'ContactName': 'Laurence Lebihan', + 'ContactTitle': 'Owner', + 'Address': '12, rue des Bouchers', + 'City': 'Marseille', + 'Region': null, + 'PostalCode': '13008', + 'Country': 'France', + 'Phone': '91.24.45.40', + 'Fax': '91.24.45.41', + 'Employees': 68, + 'DateCreated': new Date(2018, 3, 5), + 'Contract': false + }, + { + 'ID': 'BOTTM', + 'CompanyName': 'Bottom-Dollar Markets', + 'ContactName': 'Elizabeth Lincoln', + 'ContactTitle': 'Accounting Manager', + 'Address': '23 Tsawassen Blvd.', + 'City': 'Tsawassen', + 'Region': 'BC', + 'PostalCode': 'T2F 8M4', + 'Country': 'Canada', + 'Phone': '(604) 555-4729', + 'Fax': '(604) 555-3745', + 'Employees': 107, + 'DateCreated': new Date(2017, 6, 10), + 'Contract': true + }, + { + 'ID': 'BSBEV', + 'CompanyName': 'Beverages', + 'ContactName': 'Victoria Ashworth', + 'ContactTitle': 'Sales Representative', + 'Address': 'Fauntleroy Circus', + 'City': 'London', + 'Region': null, + 'PostalCode': 'EC2 5NT', + 'Country': 'UK', + 'Phone': '(171) 555-1212', + 'Fax': null, + 'Employees': 197, + 'DateCreated': new Date(2017, 10, 4), + 'Contract': true + }, + { + 'ID': 'CACTU', + 'CompanyName': + 'Cactus Comidas para llevar', + 'ContactName': 'Patricio Simpson', + 'ContactTitle': 'Sales Agent', + 'Address': 'Cerrito 333', + 'City': 'Buenos Aires', + 'Region': null, + 'PostalCode': '1010', + 'Country': 'Argentina', + 'Phone': '(1) 135-5555', + 'Fax': '(1) 135-4892', + 'Employees': 33, + 'DateCreated': new Date(2014, 5, 12), + 'Contract': false + }, + { + 'ID': 'CENTC', + 'CompanyName': 'Centro comercial Moctezuma', + 'ContactName': 'Francisco Chang', + 'ContactTitle': 'Marketing Manager', + 'Address': 'Sierras de Granada 9993', + 'City': 'México D.F.', + 'Region': null, + 'PostalCode': '05022', + 'Country': 'Mexico', + 'Phone': '(5) 555-3392', + 'Fax': '(5) 555-7293', + 'Employees': 18, + 'DateCreated': new Date(2015, 6, 27), + 'Contract': true + }, + { + 'ID': 'CHOPS', + 'CompanyName': 'Chop-suey Chinese', + 'ContactName': 'Yang Wang', + 'ContactTitle': 'Owner', + 'Address': 'Hauptstr. 29', + 'City': 'Bern', + 'Region': null, + 'PostalCode': '3012', + 'Country': 'Switzerland', + 'Phone': '0452-076545', + 'Fax': null, + 'Employees': 380, + 'DateCreated': new Date(2011, 8, 6), + 'Contract': true + }, + { + 'ID': 'COMMI', + 'CompanyName': 'Comércio Mineiro', + 'ContactName': 'Pedro Afonso', + 'ContactTitle': 'Sales Associate', + 'Address': 'Av. dos Lusíadas, 23', + 'City': 'Sao Paulo', 'Region': 'SP', + 'PostalCode': '05432-043', + 'Country': 'Brazil', + 'Phone': '(11) 555-7647', + 'Fax': null, + 'Employees': 137, + 'DateCreated': new Date(2012, 6, 10), + 'Contract': false + }, + { + 'ID': 'CONSH', + 'CompanyName': 'Consolidated Holdings', + 'ContactName': 'Elizabeth Brown', + 'ContactTitle': 'Sales Representative', + 'Address': 'Berkeley Gardens 12 Brewery', + 'City': 'London', + 'Region': null, + 'PostalCode': 'WX1 6LT', + 'Country': 'UK', + 'Phone': '(171) 555-2282', + 'Fax': '(171) 555-9199', + 'Employees': 150, + 'DateCreated': new Date(2012, 6, 10), + 'Contract': false + }, + { + 'ID': 'DRACD', + 'CompanyName': 'Drachenblut Delikatessen', + 'ContactName': 'Sven Ottlieb', + 'ContactTitle': 'Order Administrator', + 'Address': 'Walserweg 21', + 'City': 'Aachen', + 'Region': null, + 'PostalCode': '52066', + 'Country': 'Germany', + 'Phone': '0241-039123', + 'Fax': '0241-059428', + 'Employees': 265, + 'DateCreated': new Date(2014, 9, 11), + 'Contract': true + }, + { + 'ID': 'DUMON', + 'CompanyName': 'Du monde entier', + 'ContactName': 'Janine Labrune', + 'ContactTitle': 'Owner', + 'Address': '67, rue des Cinquante Otages', + 'City': 'Nantes', + 'Region': null, + 'PostalCode': '44000', + 'Country': 'France', + 'Phone': '40.67.88.88', + 'Fax': '40.67.89.89', + 'Employees': 24, + 'DateCreated': new Date(2015, 8, 4), + 'Contract': true + }, + { + 'ID': 'EASTC', + 'CompanyName': 'Eastern Connection', + 'ContactName': 'Ann Devon', + 'ContactTitle': 'Sales Agent', + 'Address': '35 King George', + 'City': 'London', + 'Region': null, + 'PostalCode': 'WX3 6FW', + 'Country': 'UK', + 'Phone': '(171) 555-0297', + 'Fax': '(171) 555-3373', + 'Employees': 123, + 'DateCreated': new Date(2013, 4, 18), + 'Contract': false + }, + { + 'ID': 'ERNSH', + 'CompanyName': + 'Ernst Handel', + 'ContactName': 'Roland Mendel', + 'ContactTitle': 'Sales Manager', + 'Address': 'Kirchgasse 6', + 'City': 'Graz', + 'Region': null, + 'PostalCode': '8010', + 'Country': 'Austria', + 'Phone': '7675-3425', + 'Fax': '7675-3426', + 'Employees': 9, + 'DateCreated': new Date(2013, 7, 9), + 'Contract': true + }, + { + 'ID': 'FAMIA', + 'CompanyName': 'Familia Arquibaldo', + 'ContactName': 'Aria Cruz', + 'ContactTitle': 'Marketing Assistant', + 'Address': 'Rua Orós, 92', + 'City': 'Sao Paulo', + 'Region': 'SP', + 'PostalCode': '05442-030', + 'Country': 'Brazil', + 'Phone': '(11) 555-9857', + 'Fax': null, + 'Employees': 67, + 'DateCreated': new Date(2015, 6, 17), + 'Contract': true + }, + { + 'ID': 'FISSA', + 'CompanyName': 'FISSA Fabrica Inter. Salchichas S.A.', + 'ContactName': 'Diego Roel', + 'ContactTitle': 'Accounting Manager', + 'Address': 'C/ Moralzarzal, 86', + 'City': 'Madrid', + 'Region': null, + 'PostalCode': '28034', + 'Country': 'Spain', + 'Phone': '(91) 555 94 44', + 'Fax': '(91) 555 55 93', + 'Employees': 87, + 'DateCreated': new Date(2017, 3, 15), + 'Contract': false + }, + { + 'ID': 'FOLIG', + 'CompanyName': 'Folies gourmandes', + 'ContactName': 'Martine Rancé', + 'ContactTitle': 'Assistant Sales Agent', + 'Address': '184, chaussée de Tournai', + 'City': 'Lille', + 'Region': null, + 'PostalCode': '59000', + 'Country': 'France', + 'Phone': '20.16.10.16', + 'Fax': '20.16.10.17', + 'Employees': 37, + 'DateCreated': new Date(2014, 5, 14), + 'Contract': false + }, + { + 'ID': 'FOLKO', + 'CompanyName': 'Folk och fä HB', + 'ContactName': 'Maria Larsson', + 'ContactTitle': 'Owner', + 'Address': 'Åkergatan 24', + 'City': 'Bräcke', + 'Region': null, + 'PostalCode': 'S-844 67', + 'Country': 'Sweden', + 'Phone': '0695-34 67 21', + 'Fax': null, + 'Employees': 42, + 'DateCreated': new Date(2011, 3, 21), + 'Contract': true + }, + { + 'ID': 'FRANK', + 'CompanyName': 'Frankenversand', + 'ContactName': 'Peter Franken', + 'ContactTitle': 'Marketing Manager', + 'Address': 'Berliner Platz 43', + 'City': 'München', + 'Region': null, + 'PostalCode': '80805', + 'Country': 'Germany', + 'Phone': '089-0877310', + 'Fax': '089-0877451', + 'Employees': 17, + 'DateCreated': new Date(2010, 7, 24), + 'Contract': true + }, + { + 'ID': 'FRANR', + 'CompanyName': 'France restauration', + 'ContactName': 'Carine Schmitt', + 'ContactTitle': 'Marketing Manager', + 'Address': '54, rue Royale', + 'City': 'Nantes', + 'Region': null, + 'PostalCode': '44000', + 'Country': 'France', + 'Phone': '40.32.21.21', + 'Fax': '40.32.21.20', + 'Employees': 20, + 'DateCreated': new Date(2011, 7, 14), + 'Contract': true + }, + { + 'ID': 'FRANS', + 'CompanyName': 'Franchi S.p.A.', + 'ContactName': 'Paolo Accorti', + 'ContactTitle': 'Sales Representative', + 'Address': 'Via Monte Bianco 34', + 'City': 'Torino', 'Region': null, + 'PostalCode': '10100', + 'Country': 'Italy', + 'Phone': '011-4988260', + 'Fax': '011-4988261', + 'Employees': 5, + 'DateCreated': new Date(2012, 8, 3), + 'Contract': false + } +]; From 1926b5ff52507723c2394f36f6ffdc03cd3366ee Mon Sep 17 00:00:00 2001 From: Radoslav Karaivanov Date: Thu, 4 Jul 2019 15:49:58 +0300 Subject: [PATCH 2/7] feat(igx-grid): Copy behavior for the grids Moved copy handler on the tbody Copy with column formatters Refactored some dead code Closes #4907 --- .../src/lib/core/grid-selection.ts | 23 ++++++++++++- .../src/lib/grids/cell.component.html | 2 +- .../src/lib/grids/cell.component.ts | 12 +------ .../src/lib/grids/grid-base.component.ts | 33 +++++++++++-------- .../src/lib/grids/grid/grid.component.html | 4 +-- .../src/lib/grids/grid/grid.component.ts | 6 ++-- .../hierarchical-grid.component.html | 2 +- .../grids/tree-grid/tree-cell.component.html | 4 +-- .../grids/tree-grid/tree-grid.component.html | 4 +-- .../grids/tree-grid/tree-grid.component.ts | 4 +-- .../grid-clipboard/grid-clipboard.sample.html | 8 ++++- .../grid-clipboard/grid-clipboard.sample.ts | 3 ++ 12 files changed, 65 insertions(+), 40 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/grid-selection.ts b/projects/igniteui-angular/src/lib/core/grid-selection.ts index 910b09ca0c7..0f75bccba32 100644 --- a/projects/igniteui-angular/src/lib/core/grid-selection.ts +++ b/projects/igniteui-angular/src/lib/core/grid-selection.ts @@ -371,11 +371,14 @@ export class IgxGridSelectionService { } } - keyboardStateOnFocus(node: ISelectionNode, emitter: EventEmitter): void { + keyboardStateOnFocus(node: ISelectionNode, emitter: EventEmitter, dom): void { const kbState = this.keyboardState; // Focus triggered by keyboard navigation if (kbState.active) { + if (isChromium()) { + this._moveSelectionChrome(dom); + } // Start generating a range if shift is hold if (kbState.shift) { this.dragSelect(node, kbState); @@ -524,4 +527,22 @@ export class IgxGridSelectionService { selection.addRange(this._selectionRange || document.createRange()); } } + + /** + * (╯°□°)╯︵ ┻━┻ + * Chrome and Chromium don't care about the active + * range after keyboard navigation, thus this. + */ + _moveSelectionChrome(node: Node) { + const selection = window.getSelection(); + selection.removeAllRanges(); + const range = new Range(); + range.selectNode(node); + range.collapse(true); + selection.addRange(range); + } +} + +export function isChromium(): boolean { + return (/Chrom|e?ium/g.test(navigator.userAgent) || /Google Inc/g.test(navigator.vendor)) && !/Edge/g.test(navigator.userAgent); } diff --git a/projects/igniteui-angular/src/lib/grids/cell.component.html b/projects/igniteui-angular/src/lib/grids/cell.component.html index 26782b1614a..68d31ad4330 100644 --- a/projects/igniteui-angular/src/lib/grids/cell.component.html +++ b/projects/igniteui-angular/src/lib/grids/cell.component.html @@ -1,5 +1,5 @@ -
{{ formatter ? formatter(value) : column.dataType === 'number' ? (value | igxdecimal: diff --git a/projects/igniteui-angular/src/lib/grids/cell.component.ts b/projects/igniteui-angular/src/lib/grids/cell.component.ts index 00b3a2b5eef..36ad1388d71 100644 --- a/projects/igniteui-angular/src/lib/grids/cell.component.ts +++ b/projects/igniteui-angular/src/lib/grids/cell.component.ts @@ -520,8 +520,6 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy { protected isInCompositionMode = false; protected compositionStartHandler; protected compositionEndHandler; - protected focusHandlerIE; - protected focusOut; private _highlight: IgxTextHighlightDirective; @@ -552,12 +550,6 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy { // Hitting Enter with IME submits and exits from edit mode instead of first closing the IME dialog this.nativeElement.addEventListener('compositionstart', this.compositionStartHandler); this.nativeElement.addEventListener('compositionend', this.compositionEndHandler); - - // https://stackoverflow.com/q/51404782 - this.focusHandlerIE = (e: FocusEvent) => this.onFocus(e); - this.focusOut = () => this.onBlur(); - this.nativeElement.addEventListener('focusin', this.focusHandlerIE); - this.nativeElement.addEventListener('focusout', this.focusOut); } }); } @@ -575,8 +567,6 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy { if (isIE()) { this.nativeElement.removeEventListener('compositionstart', this.compositionStartHandler); this.nativeElement.removeEventListener('compositionend', this.compositionEndHandler); - this.nativeElement.removeEventListener('focusin', this.focusHandlerIE); - this.nativeElement.removeEventListener('focusout', this.focusOut); } }); } @@ -792,7 +782,7 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy { } this.selectionService.primaryButton = true; - this.selectionService.keyboardStateOnFocus(node, this.grid.onRangeSelection); + this.selectionService.keyboardStateOnFocus(node, this.grid.onRangeSelection, this.nativeElement); } /** diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index 19083745c75..7a3a7c5b407 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -105,7 +105,6 @@ const MIN_ROW_EDITING_COUNT_THRESHOLD = 2; export const IgxGridTransaction = new InjectionToken('IgxGridTransaction'); export interface IGridClipboardEvent { - type: string; data: any[]; cancel: boolean; } @@ -2376,6 +2375,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements clipboardOptions = { enabled: true, copyHeaders: true, + copyFormatters: true, separator: '\t' }; @@ -2643,9 +2643,10 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements private keydownHandler(event) { const key = event.key.toLowerCase(); - if (event.ctrlKey && key === 'c' && this.clipboardOptions.enabled) { - isIE() ? this.copyHandler(null, true) : this.document.execCommand('copy'); - } + // TODO: Move in a separate handler on the `grid body`. + // if (event.ctrlKey && key === 'c' && isIE()) { + // this.copyHandler(null, true); + // } if ((isNavigationKey(key) && event.keyCode !== 32) || key === 'tab' || key === 'pagedown' || key === 'pageup') { event.preventDefault(); if (key === 'pagedown') { @@ -4854,7 +4855,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements return this.selectionService.ranges; } - extractDataFromSelection(source: any[]): any[] { + extractDataFromSelection(source: any[], applyColumnFormatters = false): any[] { let column: IgxColumnComponent; let record = {}; const selectedData = []; @@ -4875,7 +4876,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements for (const each of temp) { column = visibleColumns[each]; if (column) { - record[column.field] = source[row][column.field]; + record[column.field] = applyColumnFormatters && column.formatter ? column.formatter(source[row][column.field]) + : source[row][column.field]; } } if (Object.keys(record).length) { @@ -4886,10 +4888,9 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements return selectedData; } - getSelectedData() { + getSelectedData(applyColumnFormatters = false) { const source = this.verticalScrollContainer.igxForOf; - - return this.extractDataFromSelection(source); + return this.extractDataFromSelection(source, applyColumnFormatters); } /** @@ -4913,7 +4914,6 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements /** * @hidden */ - // @HostListener('scroll', ['$event']) public scrollHandler(event) { this.parentVirtDir.getHorizontalScroll().scrollLeft += event.target.scrollLeft; this.verticalScrollContainer.getVerticalScroll().scrollTop += event.target.scrollTop; @@ -4925,13 +4925,13 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements * @hidden * @internal */ - @HostListener('copy', ['$event']) public copyHandler(event, ie11 = false) { - if (!this.clipboardOptions.enabled) { + if (!this.clipboardOptions.enabled || this.crudService.inEditMode) { return; } - const data = this.getSelectedData(); - const ev = { type: 'copy', data, cancel: false } as IGridClipboardEvent; + + const data = this.getSelectedData(this.clipboardOptions.copyFormatters); + const ev = { data, cancel: false } as IGridClipboardEvent; this.onGridCopy.emit(ev); if (ev.cancel) { @@ -4951,6 +4951,11 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements } event.preventDefault(); + + /* Necessary for the hiearachical case but will probably have to + change how getSelectedData is propagated in the hiearachical grid + */ + event.stopPropagation(); event.clipboardData.setData('text/plain', result); } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html index c4473a72521..be0ae4014a5 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html @@ -126,7 +126,7 @@
-
+
-
\ No newline at end of file +
diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts index 45056bff522..c4264969e3b 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts @@ -879,7 +879,7 @@ export class IgxGridComponent extends IgxGridBaseComponent implements IGridDataB } } - getSelectedData(): any[] { + getSelectedData(applyColumnFormatters = false): any[] { if (this.groupingExpressions.length) { const source = []; @@ -893,9 +893,9 @@ export class IgxGridComponent extends IgxGridBaseComponent implements IGridDataB }; this.verticalScrollContainer.igxForOf.forEach(process); - return this.extractDataFromSelection(source); + return this.extractDataFromSelection(source, applyColumnFormatters); } else { - return super.getSelectedData(); + return super.getSelectedData(applyColumnFormatters); } } diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html index 20f00009248..aa3fdb686a1 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html @@ -93,7 +93,7 @@
-
+
diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.html b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.html index c1b816bba02..16fd0de224e 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.html +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.html @@ -1,5 +1,5 @@ -
{{ formatter ? formatter(value) : column.dataType === 'number' ? (value | igxdecimal: @@ -11,7 +11,7 @@ - + diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html index 8adb5c7cea5..2caea55ebd0 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html @@ -83,7 +83,7 @@ id="right" class="igx-grid__scroll-on-drag-right">
-
+
-
\ No newline at end of file +
diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts index 56258ecb51a..3a046e2e355 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts @@ -722,7 +722,7 @@ export class IgxTreeGridComponent extends IgxGridBaseComponent implements IGridD }; } - getSelectedData(): any[] { + getSelectedData(applyColumnFormatters = false): any[] { const source = []; const process = (record) => { @@ -734,7 +734,7 @@ export class IgxTreeGridComponent extends IgxGridBaseComponent implements IGridD }; this.verticalScrollContainer.igxForOf.forEach(process); - return this.extractDataFromSelection(source); + return this.extractDataFromSelection(source, applyColumnFormatters); } /** diff --git a/src/app/grid-clipboard/grid-clipboard.sample.html b/src/app/grid-clipboard/grid-clipboard.sample.html index 5a5ebd35acb..709c2d6e14a 100644 --- a/src/app/grid-clipboard/grid-clipboard.sample.html +++ b/src/app/grid-clipboard/grid-clipboard.sample.html @@ -16,13 +16,19 @@
Toggle grid copy behavior Toggle copying of header labels + Toggle copying column formatters
- + +
diff --git a/src/app/grid-clipboard/grid-clipboard.sample.ts b/src/app/grid-clipboard/grid-clipboard.sample.ts index db98204c1b1..2f5dbd7aefb 100644 --- a/src/app/grid-clipboard/grid-clipboard.sample.ts +++ b/src/app/grid-clipboard/grid-clipboard.sample.ts @@ -12,10 +12,13 @@ export class GridClipboardSampleComponent { options = { enabled: true, copyHeaders: true, + copyFormatters: true, separator: '\t' }; constructor() { this.data = SAMPLE_DATA.slice(0); } + + formatter = (value: any) => `** ${value} **`; } From d152c7c306468d805abe0c83d39f57ce95cf01cd Mon Sep 17 00:00:00 2001 From: Radoslav Karaivanov Date: Tue, 9 Jul 2019 09:40:05 +0300 Subject: [PATCH 3/7] feat(igx-grid): Copy handler for IE 11 Closes #4907 --- .../src/lib/grids/grid-base.component.ts | 9 +++++++-- .../src/lib/grids/grid/grid.component.html | 2 +- .../hierarchical-grid/hierarchical-grid.component.html | 2 +- .../src/lib/grids/tree-grid/tree-grid.component.html | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index 53d324d76ae..2f9bd47999a 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -23,8 +23,7 @@ import { ViewChildren, ViewContainerRef, InjectionToken, - Optional, - HostListener + Optional } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil, first, filter } from 'rxjs/operators'; @@ -4924,6 +4923,12 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements event.target.scrollTop = 0; } + copyHandlerIE() { + if (isIE()) { + this.copyHandler(null, true); + } + } + /** * @hidden * @internal diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html index be0ae4014a5..30251c86cb2 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html @@ -126,7 +126,7 @@
-
+
-
+
diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html index 2caea55ebd0..26809b67b4d 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html @@ -83,7 +83,7 @@ id="right" class="igx-grid__scroll-on-drag-right">
-
+
Date: Tue, 9 Jul 2019 16:51:58 +0300 Subject: [PATCH 4/7] chore(*): add clipboard tests --- .../src/lib/grids/grid/grid-clipboard.spec.ts | 172 ++++++++++++++++++ .../src/lib/test-utils/grid-samples.spec.ts | 16 ++ 2 files changed, 188 insertions(+) create mode 100644 projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts new file mode 100644 index 00000000000..5da6072e7f4 --- /dev/null +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts @@ -0,0 +1,172 @@ +import { async, fakeAsync, TestBed, tick} from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { + IgxGridModule, IgxGridComponent +} from './index'; +import { configureTestSuite } from '../../test-utils/configure-suite'; +import { IgxGridClipboardComponent } from '../../test-utils/grid-samples.spec'; +import { CancelableEventArgs } from '../../core/utils'; +import { take } from 'rxjs/operators'; + +describe('IgxGrid - Clipboard', () => { + configureTestSuite(); + let fix; + let grid: IgxGridComponent; + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + IgxGridClipboardComponent + ], + imports: [BrowserAnimationsModule, IgxGridModule, NoopAnimationsModule] + }) + .compileComponents(); + })); + + beforeEach(fakeAsync(/** height/width setter rAF */() => { + fix = TestBed.createComponent(IgxGridClipboardComponent); + fix.detectChanges(); + grid = fix.componentInstance.grid; + })); + + it('Copy data with default settings', () => { + const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); + const range = { rowStart: 0, rowEnd: 1, columnStart: 1, columnEnd: 3 }; + grid.selectRange(range); + fix.detectChanges(); + + const eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(1); + expect(eventData) + .toEqual('ProductName\tDownloads\tReleased\r\n** Ignite UI for JavaScript **\t254\tfalse\r\n** NetAdvantage **\t127\ttrue\r\n'); + }); + + it('Copy data when there are no selected cells', () => { + const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); + const eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(1); + expect(copySpy).toHaveBeenCalledWith({ + data: [], + cancel: false + }); + expect(eventData).toEqual(''); + }); + + it('Copy data with different separator', () => { + const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); + grid.clipboardOptions.separator = ';'; + grid.selectRange({ rowStart: 0, rowEnd: 0, columnStart: 0, columnEnd: 0 }); + grid.selectRange({ rowStart: 1, rowEnd: 1, columnStart: 1, columnEnd: 1 }); + fix.detectChanges(); + + let eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(1); + expect(eventData).toEqual('ID;ProductName\r\n1;\r\n;** NetAdvantage **\r\n'); + + grid.clipboardOptions.separator = ','; + fix.detectChanges(); + + eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(2); + expect(eventData).toEqual('ID,ProductName\r\n1,\r\n,** NetAdvantage **\r\n'); + }); + + it('Copy data without headers', () => { + const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); + grid.clipboardOptions.copyHeaders = false; + grid.selectRange({ rowStart: 1, rowEnd: 2, columnStart: 2, columnEnd: 3 }); + fix.detectChanges(); + + let eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(1); + expect(eventData).toEqual('127\ttrue\r\n20\t\r\n'); + + grid.clipboardOptions.copyHeaders = true; + fix.detectChanges(); + + eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(2); + expect(eventData).toEqual('Downloads\tReleased\r\n127\ttrue\r\n20\t\r\n'); + }); + + it('Disable clipboardOptions', () => { + const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); + grid.clipboardOptions.enabled = false; + grid.selectRange({ rowStart: 0, rowEnd: 2, columnStart: 0, columnEnd: 3 }); + fix.detectChanges(); + + const eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(0); + expect(eventData).toEqual(''); + }); + + it('Disable clipboardOptions', () => { + const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); + grid.clipboardOptions.enabled = false; + grid.selectRange({ rowStart: 0, rowEnd: 2, columnStart: 0, columnEnd: 3 }); + fix.detectChanges(); + + const eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(0); + expect(eventData).toEqual(''); + }); + + it('Disable copyFormatters', () => { + const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); + grid.clipboardOptions.copyFormatters = false; + grid.selectRange({ rowStart: 1, rowEnd: 3, columnStart: 1, columnEnd: 1 }); + fix.detectChanges(); + + let eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(1); + expect(eventData).toEqual('ProductName\r\nNetAdvantage\r\nIgnite UI for Angular\r\n\r\n'); + grid.clipboardOptions.copyFormatters = true; + fix.detectChanges(); + + eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(2); + expect(eventData).toEqual('ProductName\r\n** NetAdvantage **\r\n** Ignite UI for Angular **\r\n** null **\r\n'); + }); + + it('Cancel onGridCopy event ', () => { + const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); + grid.onGridCopy.pipe(take(1)).subscribe((e: CancelableEventArgs) => e.cancel = true); + grid.selectRange({ rowStart: 1, rowEnd: 3, columnStart: 0, columnEnd: 3 }); + fix.detectChanges(); + + const eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(1); + expect(copySpy).toHaveBeenCalledWith({ + data: grid.getSelectedData(true), + cancel: true + }); + expect(eventData).toEqual(''); + }); + + it('Copy when there is a cell in edit mode', fakeAsync(() => { + const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); + const cell = grid.getCellByColumn(0, 'ProductName'); + cell.nativeElement.dispatchEvent( new Event('dblclick')); + tick(16); + fix.detectChanges(); + expect(cell.editMode).toBe(true); + + grid.selectRange({ rowStart: 1, rowEnd: 3, columnStart: 0, columnEnd: 3 }); + tick(16); + fix.detectChanges(); + + expect(cell.editMode).toBe(true); + + const eventData = dispatchCopyEventOnGridBody(fix); + expect(copySpy).toHaveBeenCalledTimes(0); + expect(eventData).toEqual(''); + })); +}); + +function dispatchCopyEventOnGridBody(fixture) { + const gridBody = fixture.debugElement.query(By.css('.igx-grid__tbody')).nativeElement; + const ev = new ClipboardEvent('copy', {clipboardData: new DataTransfer}); + gridBody.dispatchEvent(ev); + fixture.detectChanges(); + return ev.clipboardData.getData('text/plain'); +} diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts index ed0227f0385..36dffa4bb48 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts @@ -1083,3 +1083,19 @@ export class IgxTestExcelFilteringDatePickerComponent extends IgxGridFilteringCo this.cd.detectChanges(); } } + +@Component({ + template: ` + + + + + + + ` +}) +export class IgxGridClipboardComponent extends BasicGridComponent { + public data = SampleTestData.excelFilteringData(); + formatter = (value: any) => `** ${value} **`; +} From 7eb1277a824dc44ed3761472bfde2be7b83b317b Mon Sep 17 00:00:00 2001 From: Radoslav Karaivanov Date: Wed, 10 Jul 2019 11:58:46 +0300 Subject: [PATCH 5/7] refactor(igx-grid): Cleaned up some method params Added docs --- .../src/lib/grids/grid-base.component.ts | 40 +++++++++++++++---- .../src/lib/grids/grid/grid.component.ts | 9 +++-- .../grids/tree-grid/tree-grid.component.ts | 7 +++- .../grid-clipboard/grid-clipboard.sample.html | 2 +- .../grid-clipboard/grid-clipboard.sample.ts | 5 +++ 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index 7feb2b9dc32..8e84ecb49d4 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -1542,7 +1542,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements public onRowDragEnd = new EventEmitter(); /** - * TODO: Write doc + * Emitted when a copy operation is executed. + * Fired only if copy behavior is enabled through the [`clipboardOptions`]{@link IgxGridBaseComponent#clipboardOptions}. */ @Output() onGridCopy = new EventEmitter(); @@ -2369,13 +2370,25 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements } /** - * TODO: Write doc + * Controls the copy behavior of the grid. */ @Input() clipboardOptions = { + /** + * Enables/disables the copy behavior + */ enabled: true, + /** + * Include the columns headers in the clipboard output. + */ copyHeaders: true, + /** + * Apply the columns formatters (if any) on the data in the clipboard output. + */ copyFormatters: true, + /** + * The separator used for formatting the copy output. Defaults to `\t`. + */ separator: '\t' }; @@ -2398,7 +2411,10 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements /* End of toolbar related definitions */ - // TODO: Document + /** + * Emitted when making a range selection either through + * drag selection or through keyboard selection. + */ @Output() onRangeSelection = new EventEmitter(); @@ -4857,7 +4873,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements return this.selectionService.ranges; } - extractDataFromSelection(source: any[], applyColumnFormatters = false): any[] { + + protected extractDataFromSelection(source: any[], formatters = false, headers = false): any[] { let columnsArray: IgxColumnComponent[]; let record = {}; const selectedData = []; @@ -4875,7 +4892,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements columnsArray = this.getSelectableColumnsAt(each); columnsArray.forEach((col) => { if (col) { - record[col.field] = applyColumnFormatters && col.formatter ? col.formatter(source[row][col.field]) + const key = headers ? col.header || col.field : col.field; + record[key] = formatters && col.formatter ? col.formatter(source[row][col.field]) : source[row][col.field]; } }); @@ -4903,9 +4921,15 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements } } - getSelectedData(applyColumnFormatters = false) { + /** + * + * Returns an array of the current cell selection in the form of `[{ column.field: cell.value }, ...]`. + * If `formatters` is enabled, the cell value will be formatted by its respective column formatter (if any). + * If `headers` is enabled, it will use the column header (if any) instead of the column field. + */ + getSelectedData(formatters = false, headers = false) { const source = this.verticalScrollContainer.igxForOf; - return this.extractDataFromSelection(source, applyColumnFormatters); + return this.extractDataFromSelection(source, formatters, headers); } /** @@ -4951,7 +4975,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements return; } - const data = this.getSelectedData(this.clipboardOptions.copyFormatters); + const data = this.getSelectedData(this.clipboardOptions.copyFormatters, this.clipboardOptions.copyHeaders); const ev = { data, cancel: false } as IGridClipboardEvent; this.onGridCopy.emit(ev); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts index 6925b6dc9b1..bc549a2adc2 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts @@ -881,7 +881,10 @@ export class IgxGridComponent extends IgxGridBaseComponent implements IGridDataB } } - getSelectedData(applyColumnFormatters = false): any[] { + /** + * @inheritdoc + */ + getSelectedData(formatters = false, headers = false): any[] { if (this.groupingExpressions.length) { const source = []; @@ -895,9 +898,9 @@ export class IgxGridComponent extends IgxGridBaseComponent implements IGridDataB }; this.verticalScrollContainer.igxForOf.forEach(process); - return this.extractDataFromSelection(source, applyColumnFormatters); + return this.extractDataFromSelection(source, formatters, headers); } else { - return super.getSelectedData(applyColumnFormatters); + return super.getSelectedData(formatters, headers); } } diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts index bfb1764e1fb..23915964927 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts @@ -729,7 +729,10 @@ export class IgxTreeGridComponent extends IgxGridBaseComponent implements IGridD }; } - getSelectedData(applyColumnFormatters = false): any[] { + /** + * @inheritdoc + */ + getSelectedData(formatters = false, headers = false): any[] { const source = []; const process = (record) => { @@ -741,7 +744,7 @@ export class IgxTreeGridComponent extends IgxGridBaseComponent implements IGridD }; this.verticalScrollContainer.igxForOf.forEach(process); - return this.extractDataFromSelection(source, applyColumnFormatters); + return this.extractDataFromSelection(source, formatters, headers); } /** diff --git a/src/app/grid-clipboard/grid-clipboard.sample.html b/src/app/grid-clipboard/grid-clipboard.sample.html index 709c2d6e14a..241be2c9b38 100644 --- a/src/app/grid-clipboard/grid-clipboard.sample.html +++ b/src/app/grid-clipboard/grid-clipboard.sample.html @@ -25,7 +25,7 @@
diff --git a/src/app/grid-clipboard/grid-clipboard.sample.ts b/src/app/grid-clipboard/grid-clipboard.sample.ts index 2f5dbd7aefb..499a52b0dc1 100644 --- a/src/app/grid-clipboard/grid-clipboard.sample.ts +++ b/src/app/grid-clipboard/grid-clipboard.sample.ts @@ -21,4 +21,9 @@ export class GridClipboardSampleComponent { } formatter = (value: any) => `** ${value} **`; + + initColumn(column) { + column.formatter = this.formatter; + column.header = `🐱‍👤 ${column.field} 🐱‍🏍`; + } } From e6cff41bfa96041457a2e84e9dd6f9ee7d6a0366 Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Wed, 10 Jul 2019 14:37:00 +0300 Subject: [PATCH 6/7] chore(*): update clipboard test --- .../src/lib/grids/grid/grid-clipboard.spec.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts index 5da6072e7f4..f43936d2610 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts @@ -37,8 +37,9 @@ describe('IgxGrid - Clipboard', () => { const eventData = dispatchCopyEventOnGridBody(fix); expect(copySpy).toHaveBeenCalledTimes(1); - expect(eventData) - .toEqual('ProductName\tDownloads\tReleased\r\n** Ignite UI for JavaScript **\t254\tfalse\r\n** NetAdvantage **\t127\ttrue\r\n'); + expect(eventData). + // tslint:disable-next-line:max-line-length + toEqual('ProductNameHeader\tDownloads\tReleased\r\n** Ignite UI for JavaScript **\t254\tfalse\r\n** NetAdvantage **\t127\ttrue\r\n'); }); it('Copy data when there are no selected cells', () => { @@ -61,14 +62,14 @@ describe('IgxGrid - Clipboard', () => { let eventData = dispatchCopyEventOnGridBody(fix); expect(copySpy).toHaveBeenCalledTimes(1); - expect(eventData).toEqual('ID;ProductName\r\n1;\r\n;** NetAdvantage **\r\n'); + expect(eventData).toEqual('ID;ProductNameHeader\r\n1;\r\n;** NetAdvantage **\r\n'); grid.clipboardOptions.separator = ','; fix.detectChanges(); eventData = dispatchCopyEventOnGridBody(fix); expect(copySpy).toHaveBeenCalledTimes(2); - expect(eventData).toEqual('ID,ProductName\r\n1,\r\n,** NetAdvantage **\r\n'); + expect(eventData).toEqual('ID,ProductNameHeader\r\n1,\r\n,** NetAdvantage **\r\n'); }); it('Copy data without headers', () => { @@ -119,13 +120,13 @@ describe('IgxGrid - Clipboard', () => { let eventData = dispatchCopyEventOnGridBody(fix); expect(copySpy).toHaveBeenCalledTimes(1); - expect(eventData).toEqual('ProductName\r\nNetAdvantage\r\nIgnite UI for Angular\r\n\r\n'); + expect(eventData).toEqual('ProductNameHeader\r\nNetAdvantage\r\nIgnite UI for Angular\r\n\r\n'); grid.clipboardOptions.copyFormatters = true; fix.detectChanges(); eventData = dispatchCopyEventOnGridBody(fix); expect(copySpy).toHaveBeenCalledTimes(2); - expect(eventData).toEqual('ProductName\r\n** NetAdvantage **\r\n** Ignite UI for Angular **\r\n** null **\r\n'); + expect(eventData).toEqual('ProductNameHeader\r\n** NetAdvantage **\r\n** Ignite UI for Angular **\r\n** null **\r\n'); }); it('Cancel onGridCopy event ', () => { @@ -137,7 +138,7 @@ describe('IgxGrid - Clipboard', () => { const eventData = dispatchCopyEventOnGridBody(fix); expect(copySpy).toHaveBeenCalledTimes(1); expect(copySpy).toHaveBeenCalledWith({ - data: grid.getSelectedData(true), + data: grid.getSelectedData(true, true), cancel: true }); expect(eventData).toEqual(''); From c10a0bbc43b61a65571247fcad92b9f4501bba64 Mon Sep 17 00:00:00 2001 From: Nadia Robakova Date: Wed, 10 Jul 2019 15:40:54 +0300 Subject: [PATCH 7/7] chore(*): remove diplicate test --- .../src/lib/grids/grid/grid-clipboard.spec.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts index f43936d2610..84f29d41274 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-clipboard.spec.ts @@ -101,17 +101,6 @@ describe('IgxGrid - Clipboard', () => { expect(eventData).toEqual(''); }); - it('Disable clipboardOptions', () => { - const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); - grid.clipboardOptions.enabled = false; - grid.selectRange({ rowStart: 0, rowEnd: 2, columnStart: 0, columnEnd: 3 }); - fix.detectChanges(); - - const eventData = dispatchCopyEventOnGridBody(fix); - expect(copySpy).toHaveBeenCalledTimes(0); - expect(eventData).toEqual(''); - }); - it('Disable copyFormatters', () => { const copySpy = spyOn(grid.onGridCopy, 'emit').and.callThrough(); grid.clipboardOptions.copyFormatters = false;